/* * 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 "FileReaderSync.h" #include "Base64.h" #include "Blob.h" #include "BlobURL.h" #include "FileReader.h" #include "ResourceRequest.h" #include "ResourceResponse.h" #include "ScriptExecutionContext.h" #include "TextEncoding.h" #include "TextResourceDecoder.h" #include "ThreadableBlobRegistry.h" #include "ThreadableLoader.h" namespace WebCore { class FileReaderSyncLoader : public ThreadableLoaderClient { public: // If the output result is provided, use it. Otherwise, save it as the raw data. FileReaderSyncLoader(StringBuilder*); // Returns the http status code. void start(ScriptExecutionContext*, const ResourceRequest&, ExceptionCode&); // ThreadableLoaderClient virtual void didReceiveResponse(const ResourceResponse&); virtual void didReceiveData(const char*, int); virtual void didFinishLoading(unsigned long identifier); virtual void didFail(const ResourceError&); const Vector& rawData() const { return m_rawData; } private: // The output result. The caller provides this in order to load the binary data directly. StringBuilder* m_builder; // The raw data. The caller does not provide the above output result and we need to save it here. Vector m_rawData; int m_httpStatusCode; }; FileReaderSyncLoader::FileReaderSyncLoader(StringBuilder* builder) : m_builder(builder) , m_httpStatusCode(0) { } void FileReaderSyncLoader::start(ScriptExecutionContext* scriptExecutionContext, const ResourceRequest& request, ExceptionCode& ec) { ThreadableLoaderOptions options; options.sendLoadCallbacks = true; options.sniffContent = false; options.forcePreflight = false; options.allowCredentials = true; options.crossOriginRequestPolicy = DenyCrossOriginRequests; ThreadableLoader::loadResourceSynchronously(scriptExecutionContext, request, *this, options); ec = (m_httpStatusCode == 200) ? 0 : FileReader::httpStatusCodeToExceptionCode(m_httpStatusCode); } void FileReaderSyncLoader::didReceiveResponse(const ResourceResponse& response) { m_httpStatusCode = response.httpStatusCode(); } void FileReaderSyncLoader::didReceiveData(const char* data, int lengthReceived) { if (m_builder) m_builder->append(data, static_cast(lengthReceived)); else m_rawData.append(data, static_cast(lengthReceived)); } void FileReaderSyncLoader::didFinishLoading(unsigned long) { } void FileReaderSyncLoader::didFail(const ResourceError&) { // Treat as internal error. m_httpStatusCode = 500; } String FileReaderSync::readAsBinaryString(ScriptExecutionContext* scriptExecutionContext, Blob* blob, ExceptionCode& ec) { if (!blob) return m_builder.toString(); read(scriptExecutionContext, blob, ReadAsBinaryString, ec); return m_builder.toString(); } String FileReaderSync::readAsText(ScriptExecutionContext* scriptExecutionContext, Blob* blob, const String& encoding, ExceptionCode& ec) { if (!blob) return m_builder.toString(); m_encoding = encoding; read(scriptExecutionContext, blob, ReadAsText, ec); return m_builder.toString(); } String FileReaderSync::readAsDataURL(ScriptExecutionContext* scriptExecutionContext, Blob* blob, ExceptionCode& ec) { if (!blob) return m_builder.toString(); read(scriptExecutionContext, blob, ReadAsDataURL, ec); return m_builder.toString(); } void FileReaderSync::read(ScriptExecutionContext* scriptExecutionContext, Blob* blob, ReadType readType, ExceptionCode& ec) { // The blob is read by routing through the request handling layer given the temporary public url. KURL urlForReading = BlobURL::createPublicURL(scriptExecutionContext->securityOrigin()); ThreadableBlobRegistry::registerBlobURL(urlForReading, blob->url()); ResourceRequest request(urlForReading); request.setHTTPMethod("GET"); FileReaderSyncLoader loader((readType == ReadAsBinaryString) ? &m_builder : 0); loader.start(scriptExecutionContext, request, ec); ThreadableBlobRegistry::unregisterBlobURL(urlForReading); if (ec) return; switch (readType) { case ReadAsBinaryString: // Nothing to do since we need no conversion. return; case ReadAsText: convertToText(loader.rawData().data(), loader.rawData().size(), m_builder); return; case ReadAsDataURL: FileReader::convertToDataURL(loader.rawData(), blob->type(), m_builder); return; } ASSERT_NOT_REACHED(); } void FileReaderSync::convertToText(const char* data, int size, StringBuilder& builder) { if (!size) 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 have the BOM override the // provided encoding. // FIXME: consider supporting incremental decoding to improve the perf. RefPtr decoder = TextResourceDecoder::create("text/plain", m_encoding.isEmpty() ? UTF8Encoding() : TextEncoding(m_encoding)); builder.clear(); builder.append(decoder->decode(data, size)); builder.append(decoder->flush()); } } // namespace WebCore #endif // ENABLE(BLOB)