Fix the incorrect behavior touch sound on single tap event.
[framework/web/webkit-efl.git] / Source / WebCore / fileapi / FileReaderLoader.cpp
1 /*
2  * Copyright (C) 2010 Google Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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.
17  *
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.
29  */
30
31 #include "config.h"
32
33 #if ENABLE(BLOB)
34
35 #include "FileReaderLoader.h"
36
37 #include "Blob.h"
38 #include "BlobURL.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>
52
53 using namespace std;
54
55 namespace WebCore {
56
57 FileReaderLoader::FileReaderLoader(ReadType readType, FileReaderLoaderClient* client)
58     : m_readType(readType)
59     , m_client(client)
60     , m_isRawDataConverted(false)
61     , m_stringResult("")
62     , m_bytesLoaded(0)
63     , m_totalBytes(0)
64     , m_errorCode(0)
65 {
66 }
67
68 FileReaderLoader::~FileReaderLoader()
69 {
70     terminate();
71     if (!m_urlForReading.isEmpty())
72         ThreadableBlobRegistry::unregisterBlobURL(m_urlForReading);
73 }
74
75 void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, Blob* blob)
76 {
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);
81         return;
82     }
83     ThreadableBlobRegistry::registerBlobURL(scriptExecutionContext->securityOrigin(), m_urlForReading, blob->url());
84
85     // Construct and load the request.
86     ResourceRequest request(m_urlForReading);
87     request.setHTTPMethod("GET");
88
89     ThreadableLoaderOptions options;
90     options.sendLoadCallbacks = SendCallbacks;
91     options.sniffContent = DoNotSniffContent;
92     options.preflightPolicy = ConsiderPreflight;
93     options.allowCredentials = AllowStoredCredentials;
94     options.crossOriginRequestPolicy = DenyCrossOriginRequests;
95
96     if (m_client)
97         m_loader = ThreadableLoader::create(scriptExecutionContext, this, request, options);
98     else
99         ThreadableLoader::loadResourceSynchronously(scriptExecutionContext, request, *this, options);
100 }
101
102 void FileReaderLoader::cancel()
103 {
104     m_errorCode = FileError::ABORT_ERR;
105     terminate();
106 }
107
108 void FileReaderLoader::terminate()
109 {
110     if (m_loader) {
111         m_loader->cancel();
112         cleanup();
113     }
114 }
115
116 void FileReaderLoader::cleanup()
117 {
118     m_loader = 0;
119
120     // If we get any error, we do not need to keep a buffer around.
121     if (m_errorCode) {
122         m_rawData = 0;
123         m_stringResult = "";
124     }
125 }
126
127 void FileReaderLoader::didReceiveResponse(unsigned long, const ResourceResponse& response)
128 {
129     if (response.httpStatusCode() != 200) {
130         failed(httpStatusCodeToErrorCode(response.httpStatusCode()));
131         return;
132     }
133
134     unsigned long long length = response.expectedContentLength();
135
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);
141         return;
142     }
143
144     ASSERT(!m_rawData);
145     m_rawData = ArrayBuffer::create(static_cast<unsigned>(length), 1);
146
147     if (!m_rawData) {
148         failed(FileError::NOT_READABLE_ERR);
149         return;
150     }
151
152     m_totalBytes = static_cast<unsigned>(length);
153
154     if (m_client)
155         m_client->didStartLoading();
156 }
157
158 void FileReaderLoader::didReceiveData(const char* data, int dataLength)
159 {
160     ASSERT(data);
161     ASSERT(dataLength > 0);
162
163     // Bail out if we already encountered an error.
164     if (m_errorCode)
165         return;
166
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);
171
172     if (length <= 0)
173         return;
174
175     memcpy(static_cast<char*>(m_rawData->data()) + m_bytesLoaded, data, length);
176     m_bytesLoaded += length;
177
178     m_isRawDataConverted = false;
179
180     if (m_client)
181         m_client->didReceiveData();
182 }
183
184 void FileReaderLoader::didFinishLoading(unsigned long, double)
185 {
186     cleanup();
187     if (m_client)
188         m_client->didFinishLoading();
189 }
190
191 void FileReaderLoader::didFail(const ResourceError&)
192 {
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)
195         return;
196
197     failed(FileError::NOT_READABLE_ERR);
198 }
199
200 void FileReaderLoader::failed(int errorCode)
201 {
202     m_errorCode = errorCode;
203     cleanup();
204     if (m_client)
205         m_client->didFail(m_errorCode);
206 }
207
208 FileError::ErrorCode FileReaderLoader::httpStatusCodeToErrorCode(int httpStatusCode)
209 {
210     switch (httpStatusCode) {
211     case 403:
212         return FileError::SECURITY_ERR;
213     case 404:
214         return FileError::NOT_FOUND_ERR;
215     default:
216         return FileError::NOT_READABLE_ERR;
217     }
218 }
219
220 PassRefPtr<ArrayBuffer> FileReaderLoader::arrayBufferResult() const
221 {
222     ASSERT(m_readType == ReadAsArrayBuffer);
223
224     // If the loading is not started or an error occurs, return an empty result.
225     if (!m_rawData || m_errorCode)
226         return 0;
227
228     // If completed, we can simply return our buffer.
229     if (isCompleted())
230         return m_rawData;
231
232     // Otherwise, return a copy.
233     return ArrayBuffer::create(m_rawData.get());
234 }
235
236 String FileReaderLoader::stringResult()
237 {
238     ASSERT(m_readType != ReadAsArrayBuffer);
239
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;
243
244     // If already converted from the raw data, return the result now.
245     if (m_isRawDataConverted)
246         return m_stringResult;
247
248     switch (m_readType) {
249     case ReadAsArrayBuffer:
250         // No conversion is needed.
251         break;
252     case ReadAsBinaryString:
253         m_stringResult = String(static_cast<const char*>(m_rawData->data()), m_bytesLoaded);
254         break;
255     case ReadAsText:
256         convertToText();
257         break;
258     case ReadAsDataURL:
259         // Partial data is not supported when reading as data URL.
260         if (isCompleted())
261             convertToDataURL();
262         break;
263     default:
264         ASSERT_NOT_REACHED();
265     }
266     
267     return m_stringResult;
268 }
269
270 void FileReaderLoader::convertToText()
271 {
272     if (!m_bytesLoaded)
273         return;
274
275     // Decode the data.
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;
281     if (!m_decoder)
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));
284
285     if (isCompleted())
286         builder.append(m_decoder->flush());
287
288     m_stringResult = builder.toString();
289 }
290
291 void FileReaderLoader::convertToDataURL()
292 {
293     StringBuilder builder;
294     builder.append("data:");
295
296     if (!m_bytesLoaded) {
297         m_stringResult = builder.toString();
298         return;
299     }
300
301     builder.append(m_dataType);
302     builder.append(";base64,");
303
304     Vector<char> out;
305     base64Encode(static_cast<const char*>(m_rawData->data()), m_bytesLoaded, out);
306     out.append('\0');
307     builder.append(out.data());
308
309     m_stringResult = builder.toString();
310 }
311
312 bool FileReaderLoader::isCompleted() const
313 {
314     return m_bytesLoaded == m_totalBytes;
315 }
316
317 void FileReaderLoader::setEncoding(const String& encoding)
318 {
319     if (!encoding.isEmpty())
320         m_encoding = TextEncoding(encoding);
321 }
322
323 } // namespace WebCore
324  
325 #endif // ENABLE(BLOB)