summaryrefslogtreecommitdiffstats
path: root/WebCore/fileapi/FileReaderLoader.cpp
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2010-11-04 12:00:17 -0700
committerJohn Reck <jreck@google.com>2010-11-09 11:35:04 -0800
commite14391e94c850b8bd03680c23b38978db68687a8 (patch)
tree3fed87e6620fecaf3edc7259ae58a11662bedcb2 /WebCore/fileapi/FileReaderLoader.cpp
parent1bd705833a68f07850cf7e204b26f8d328d16951 (diff)
downloadexternal_webkit-e14391e94c850b8bd03680c23b38978db68687a8.zip
external_webkit-e14391e94c850b8bd03680c23b38978db68687a8.tar.gz
external_webkit-e14391e94c850b8bd03680c23b38978db68687a8.tar.bz2
Merge Webkit at r70949: Initial merge by git.
Change-Id: I77b8645c083b5d0da8dba73ed01d4014aab9848e
Diffstat (limited to 'WebCore/fileapi/FileReaderLoader.cpp')
-rw-r--r--WebCore/fileapi/FileReaderLoader.cpp302
1 files changed, 302 insertions, 0 deletions
diff --git a/WebCore/fileapi/FileReaderLoader.cpp b/WebCore/fileapi/FileReaderLoader.cpp
new file mode 100644
index 0000000..dcd5860
--- /dev/null
+++ b/WebCore/fileapi/FileReaderLoader.cpp
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(BLOB)
+
+#include "FileReaderLoader.h"
+
+#include "ArrayBuffer.h"
+#include "Base64.h"
+#include "Blob.h"
+#include "BlobURL.h"
+#include "FileReaderLoaderClient.h"
+#include "ResourceRequest.h"
+#include "ResourceResponse.h"
+#include "ScriptExecutionContext.h"
+#include "TextResourceDecoder.h"
+#include "ThreadableBlobRegistry.h"
+#include "ThreadableLoader.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+FileReaderLoader::FileReaderLoader(ReadType readType, FileReaderLoaderClient* client)
+ : m_readType(readType)
+ , m_client(client)
+ , m_isRawDataConverted(false)
+ , m_stringResult("")
+ , m_bytesLoaded(0)
+ , m_totalBytes(0)
+ , m_errorCode(0)
+{
+}
+
+FileReaderLoader::~FileReaderLoader()
+{
+ terminate();
+ ThreadableBlobRegistry::unregisterBlobURL(m_urlForReading);
+}
+
+void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, Blob* blob)
+{
+ // The blob is read by routing through the request handling layer given a temporary public url.
+ m_urlForReading = BlobURL::createPublicURL(scriptExecutionContext->securityOrigin());
+ ThreadableBlobRegistry::registerBlobURL(m_urlForReading, blob->url());
+
+ // Construct and load the request.
+ ResourceRequest request(m_urlForReading);
+ request.setHTTPMethod("GET");
+
+ ThreadableLoaderOptions options;
+ options.sendLoadCallbacks = true;
+ options.sniffContent = false;
+ options.forcePreflight = false;
+ options.allowCredentials = true;
+ options.crossOriginRequestPolicy = DenyCrossOriginRequests;
+
+ if (m_client)
+ m_loader = ThreadableLoader::create(scriptExecutionContext, this, request, options);
+ else
+ ThreadableLoader::loadResourceSynchronously(scriptExecutionContext, request, *this, options);
+}
+
+void FileReaderLoader::cancel()
+{
+ m_errorCode = FileError::ABORT_ERR;
+ terminate();
+}
+
+void FileReaderLoader::terminate()
+{
+ if (m_loader) {
+ m_loader->cancel();
+ cleanup();
+ }
+}
+
+void FileReaderLoader::cleanup()
+{
+ m_loader = 0;
+
+ // If we get any error, we do not need to keep a buffer around.
+ if (m_errorCode) {
+ m_rawData = 0;
+ m_stringResult = "";
+ }
+}
+
+void FileReaderLoader::didReceiveResponse(const ResourceResponse& response)
+{
+ if (response.httpStatusCode() != 200) {
+ failed(httpStatusCodeToErrorCode(response.httpStatusCode()));
+ return;
+ }
+
+ // FIXME: Support reading more than the current size limit of ArrayBuffer.
+ if (static_cast<unsigned long long>(response.expectedContentLength()) > std::numeric_limits<unsigned>::max()) {
+ failed(FileError::NOT_READABLE_ERR);
+ return;
+ }
+ m_totalBytes = static_cast<unsigned>(response.expectedContentLength());
+
+ ASSERT(!m_rawData);
+ m_rawData = ArrayBuffer::create(static_cast<unsigned>(m_totalBytes), 1);
+
+ if (m_client)
+ m_client->didStartLoading();
+}
+
+void FileReaderLoader::didReceiveData(const char* data, int lengthReceived)
+{
+ ASSERT(data && lengthReceived > 0);
+
+ // Bail out if we encounter an error.
+ if (m_errorCode)
+ return;
+
+ memcpy(static_cast<char*>(m_rawData->data()) + static_cast<unsigned>(m_bytesLoaded), data, static_cast<unsigned>(lengthReceived));
+ m_bytesLoaded += static_cast<unsigned>(lengthReceived);
+
+ m_isRawDataConverted = false;
+
+ if (m_client)
+ m_client->didReceiveData();
+}
+
+void FileReaderLoader::didFinishLoading(unsigned long)
+{
+ cleanup();
+ if (m_client)
+ m_client->didFinishLoading();
+}
+
+void FileReaderLoader::didFail(const ResourceError&)
+{
+ // If we're aborting, do not proceed with normal error handling since it is covered in aborting code.
+ if (m_errorCode == FileError::ABORT_ERR)
+ return;
+
+ failed(FileError::NOT_READABLE_ERR);
+}
+
+void FileReaderLoader::failed(int errorCode)
+{
+ m_errorCode = errorCode;
+ cleanup();
+ if (m_client)
+ m_client->didFail(m_errorCode);
+}
+
+FileError::ErrorCode FileReaderLoader::httpStatusCodeToErrorCode(int httpStatusCode)
+{
+ switch (httpStatusCode) {
+ case 403:
+ return FileError::SECURITY_ERR;
+ case 404:
+ return FileError::NOT_FOUND_ERR;
+ default:
+ return FileError::NOT_READABLE_ERR;
+ }
+}
+
+PassRefPtr<ArrayBuffer> FileReaderLoader::arrayBufferResult() const
+{
+ ASSERT(m_readType == ReadAsArrayBuffer);
+
+ // If the loading is not started or an error occurs, return an empty result.
+ if (!m_rawData || m_errorCode)
+ return 0;
+
+ // If completed, we can simply return our buffer.
+ if (isCompleted())
+ return m_rawData;
+
+ // Otherwise, return a copy.
+ return ArrayBuffer::create(m_rawData.get());
+}
+
+String FileReaderLoader::stringResult()
+{
+ ASSERT(m_readType != ReadAsArrayBuffer);
+
+ // If the loading is not started or an error occurs, return an empty result.
+ if (!m_rawData || m_errorCode)
+ return m_stringResult;
+
+ // If already converted from the raw data, return the result now.
+ if (m_isRawDataConverted)
+ return m_stringResult;
+
+ switch (m_readType) {
+ case ReadAsArrayBuffer:
+ // No conversion is needed.
+ break;
+ case ReadAsBinaryString:
+ m_stringResult = String(static_cast<const char*>(m_rawData->data()), m_bytesLoaded);
+ break;
+ case ReadAsText:
+ convertToText();
+ break;
+ case ReadAsDataURL:
+ // Partial data is not supported when reading as data URL.
+ if (isCompleted())
+ convertToDataURL();
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return m_stringResult;
+}
+
+void FileReaderLoader::convertToText()
+{
+ if (!m_bytesLoaded)
+ return;
+
+ // Decode the data.
+ // The File API spec says that we should use the supplied encoding if it is valid. However, we choose to ignore this
+ // requirement in order to be consistent with how WebKit decodes the web content: always has the BOM override the
+ // provided encoding.
+ // FIXME: consider supporting incremental decoding to improve the perf.
+ StringBuilder builder;
+ if (!m_decoder)
+ m_decoder = TextResourceDecoder::create("text/plain", m_encoding.isValid() ? m_encoding : UTF8Encoding());
+ builder.append(m_decoder->decode(static_cast<const char*>(m_rawData->data()), m_bytesLoaded));
+
+ if (isCompleted())
+ builder.append(m_decoder->flush());
+
+ m_stringResult = builder.toString();
+}
+
+void FileReaderLoader::convertToDataURL()
+{
+ StringBuilder builder;
+ builder.append("data:");
+
+ if (!m_bytesLoaded) {
+ m_stringResult = builder.toString();
+ return;
+ }
+
+ if (!m_dataType.isEmpty()) {
+ builder.append(m_dataType);
+ builder.append(";base64,");
+ } else
+ builder.append("base64,");
+
+ Vector<char> out;
+ base64Encode(static_cast<const char*>(m_rawData->data()), m_bytesLoaded, out);
+ out.append('\0');
+ builder.append(out.data());
+
+ m_stringResult = builder.toString();
+}
+
+bool FileReaderLoader::isCompleted() const
+{
+ return m_bytesLoaded == m_totalBytes;
+}
+
+void FileReaderLoader::setEncoding(const String& encoding)
+{
+ if (!encoding.isEmpty())
+ m_encoding = TextEncoding(encoding);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(BLOB)