diff options
author | John Reck <jreck@google.com> | 2010-11-04 12:00:17 -0700 |
---|---|---|
committer | John Reck <jreck@google.com> | 2010-11-09 11:35:04 -0800 |
commit | e14391e94c850b8bd03680c23b38978db68687a8 (patch) | |
tree | 3fed87e6620fecaf3edc7259ae58a11662bedcb2 /WebCore/fileapi/FileReaderLoader.cpp | |
parent | 1bd705833a68f07850cf7e204b26f8d328d16951 (diff) | |
download | external_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.cpp | 302 |
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) |