- add third_party src.
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 #include "core/fileapi/FileReaderLoader.h"
34
35 #include "FetchInitiatorTypeNames.h"
36 #include "core/dom/ExecutionContext.h"
37 #include "core/fetch/TextResourceDecoder.h"
38 #include "core/fileapi/Blob.h"
39 #include "core/fileapi/FileReaderLoaderClient.h"
40 #include "core/fileapi/Stream.h"
41 #include "core/loader/ThreadableLoader.h"
42 #include "platform/blob/BlobRegistry.h"
43 #include "platform/blob/BlobURL.h"
44 #include "platform/network/ResourceRequest.h"
45 #include "platform/network/ResourceResponse.h"
46 #include "wtf/ArrayBuffer.h"
47 #include "wtf/PassOwnPtr.h"
48 #include "wtf/PassRefPtr.h"
49 #include "wtf/RefPtr.h"
50 #include "wtf/Vector.h"
51 #include "wtf/text/Base64.h"
52 #include "wtf/text/StringBuilder.h"
53
54 using namespace std;
55
56 namespace WebCore {
57
58 FileReaderLoader::FileReaderLoader(ReadType readType, FileReaderLoaderClient* client)
59     : m_readType(readType)
60     , m_client(client)
61     , m_urlForReadingIsStream(false)
62     , m_isRawDataConverted(false)
63     , m_stringResult("")
64     , m_finishedLoading(false)
65     , m_bytesLoaded(0)
66     , m_totalBytes(-1)
67     , m_hasRange(false)
68     , m_rangeStart(0)
69     , m_rangeEnd(0)
70     , m_errorCode(FileError::OK)
71 {
72 }
73
74 FileReaderLoader::~FileReaderLoader()
75 {
76     terminate();
77     if (!m_urlForReading.isEmpty()) {
78         if (m_urlForReadingIsStream)
79             BlobRegistry::unregisterStreamURL(m_urlForReading);
80         else
81             BlobRegistry::revokePublicBlobURL(m_urlForReading);
82     }
83 }
84
85 void FileReaderLoader::startInternal(ExecutionContext* executionContext, const Stream* stream, PassRefPtr<BlobDataHandle> blobData)
86 {
87     // The blob is read by routing through the request handling layer given a temporary public url.
88     m_urlForReading = BlobURL::createPublicURL(executionContext->securityOrigin());
89     if (m_urlForReading.isEmpty()) {
90         failed(FileError::SECURITY_ERR);
91         return;
92     }
93
94     if (blobData) {
95         ASSERT(!stream);
96         BlobRegistry::registerPublicBlobURL(executionContext->securityOrigin(), m_urlForReading, blobData);
97     } else {
98         ASSERT(stream);
99         BlobRegistry::registerStreamURL(executionContext->securityOrigin(), m_urlForReading, stream->url());
100     }
101
102     // Construct and load the request.
103     ResourceRequest request(m_urlForReading);
104     request.setHTTPMethod("GET");
105     if (m_hasRange)
106         request.setHTTPHeaderField("Range", String::format("bytes=%d-%d", m_rangeStart, m_rangeEnd));
107
108     ThreadableLoaderOptions options;
109     options.sendLoadCallbacks = SendCallbacks;
110     options.sniffContent = DoNotSniffContent;
111     options.preflightPolicy = ConsiderPreflight;
112     options.allowCredentials = AllowStoredCredentials;
113     options.crossOriginRequestPolicy = DenyCrossOriginRequests;
114     // FIXME: Is there a directive to which this load should be subject?
115     options.contentSecurityPolicyEnforcement = DoNotEnforceContentSecurityPolicy;
116     // Use special initiator to hide the request from the inspector.
117     options.initiator = FetchInitiatorTypeNames::internal;
118
119     if (m_client)
120         m_loader = ThreadableLoader::create(executionContext, this, request, options);
121     else
122         ThreadableLoader::loadResourceSynchronously(executionContext, request, *this, options);
123 }
124
125 void FileReaderLoader::start(ExecutionContext* executionContext, PassRefPtr<BlobDataHandle> blobData)
126 {
127     m_urlForReadingIsStream = false;
128     startInternal(executionContext, 0, blobData);
129 }
130
131 void FileReaderLoader::start(ExecutionContext* executionContext, const Stream& stream, unsigned readSize)
132 {
133     if (readSize > 0) {
134         m_hasRange = true;
135         m_rangeStart = 0;
136         m_rangeEnd = readSize - 1; // End is inclusive so (0,0) is a 1-byte read.
137     }
138
139     m_urlForReadingIsStream = true;
140     startInternal(executionContext, &stream, 0);
141 }
142
143 void FileReaderLoader::cancel()
144 {
145     m_errorCode = FileError::ABORT_ERR;
146     terminate();
147 }
148
149 void FileReaderLoader::terminate()
150 {
151     if (m_loader) {
152         m_loader->cancel();
153         cleanup();
154     }
155 }
156
157 void FileReaderLoader::cleanup()
158 {
159     m_loader = 0;
160
161     // If we get any error, we do not need to keep a buffer around.
162     if (m_errorCode) {
163         m_rawData.clear();
164         m_stringResult = "";
165         m_isRawDataConverted = true;
166         m_decoder = 0;
167     }
168 }
169
170 void FileReaderLoader::didReceiveResponse(unsigned long, const ResourceResponse& response)
171 {
172     if (response.httpStatusCode() != 200) {
173         failed(httpStatusCodeToErrorCode(response.httpStatusCode()));
174         return;
175     }
176
177     // A negative value means that the content length wasn't specified.
178     m_totalBytes = response.expectedContentLength();
179
180     long long initialBufferLength = -1;
181
182     if (m_totalBytes >= 0) {
183         initialBufferLength = m_totalBytes;
184     } else if (m_hasRange) {
185         // Set m_totalBytes and allocate a buffer based on the specified range.
186         m_totalBytes = 1LL + m_rangeEnd - m_rangeStart;
187         initialBufferLength = m_totalBytes;
188     } else {
189         // Nothing is known about the size of the resource. Normalize
190         // m_totalBytes to -1 and initialize the buffer for receiving with the
191         // default size.
192         m_totalBytes = -1;
193     }
194
195     ASSERT(!m_rawData);
196
197     if (m_readType != ReadByClient) {
198         // Check that we can cast to unsigned since we have to do
199         // so to call ArrayBuffer's create function.
200         // FIXME: Support reading more than the current size limit of ArrayBuffer.
201         if (initialBufferLength > numeric_limits<unsigned>::max()) {
202             failed(FileError::NOT_READABLE_ERR);
203             return;
204         }
205
206         if (initialBufferLength < 0) {
207             m_rawData = adoptPtr(new ArrayBufferBuilder());
208         } else {
209             m_rawData = adoptPtr(new ArrayBufferBuilder(static_cast<unsigned>(initialBufferLength)));
210             // Total size is known. Set m_rawData to ignore overflowed data.
211             m_rawData->setVariableCapacity(false);
212         }
213
214         if (!m_rawData) {
215             failed(FileError::NOT_READABLE_ERR);
216             return;
217         }
218     }
219
220     if (m_client)
221         m_client->didStartLoading();
222 }
223
224 void FileReaderLoader::didReceiveData(const char* data, int dataLength)
225 {
226     ASSERT(data);
227     ASSERT(dataLength > 0);
228
229     // Bail out if we already encountered an error.
230     if (m_errorCode)
231         return;
232
233     if (m_readType == ReadByClient) {
234         m_bytesLoaded += dataLength;
235
236         if (m_client)
237             m_client->didReceiveDataForClient(data, dataLength);
238         return;
239     }
240
241     unsigned bytesAppended = m_rawData->append(data, static_cast<unsigned>(dataLength));
242     if (!bytesAppended) {
243         m_rawData.clear();
244         m_bytesLoaded = 0;
245         failed(FileError::NOT_READABLE_ERR);
246         return;
247     }
248     m_bytesLoaded += bytesAppended;
249     m_isRawDataConverted = false;
250
251     if (m_client)
252         m_client->didReceiveData();
253 }
254
255 void FileReaderLoader::didFinishLoading(unsigned long, double)
256 {
257     if (m_readType != ReadByClient && m_rawData) {
258         m_rawData->shrinkToFit();
259         m_isRawDataConverted = false;
260     }
261
262     if (m_totalBytes == -1) {
263         // Update m_totalBytes only when in dynamic buffer grow mode.
264         m_totalBytes = m_bytesLoaded;
265     }
266
267     m_finishedLoading = true;
268
269     cleanup();
270     if (m_client)
271         m_client->didFinishLoading();
272 }
273
274 void FileReaderLoader::didFail(const ResourceError&)
275 {
276     // If we're aborting, do not proceed with normal error handling since it is covered in aborting code.
277     if (m_errorCode == FileError::ABORT_ERR)
278         return;
279
280     failed(FileError::NOT_READABLE_ERR);
281 }
282
283 void FileReaderLoader::failed(FileError::ErrorCode errorCode)
284 {
285     m_errorCode = errorCode;
286     cleanup();
287     if (m_client)
288         m_client->didFail(m_errorCode);
289 }
290
291 FileError::ErrorCode FileReaderLoader::httpStatusCodeToErrorCode(int httpStatusCode)
292 {
293     switch (httpStatusCode) {
294     case 403:
295         return FileError::SECURITY_ERR;
296     case 404:
297         return FileError::NOT_FOUND_ERR;
298     default:
299         return FileError::NOT_READABLE_ERR;
300     }
301 }
302
303 PassRefPtr<ArrayBuffer> FileReaderLoader::arrayBufferResult() const
304 {
305     ASSERT(m_readType == ReadAsArrayBuffer);
306
307     // If the loading is not started or an error occurs, return an empty result.
308     if (!m_rawData || m_errorCode)
309         return 0;
310
311     return m_rawData->toArrayBuffer();
312 }
313
314 String FileReaderLoader::stringResult()
315 {
316     ASSERT(m_readType != ReadAsArrayBuffer && m_readType != ReadAsBlob && m_readType != ReadByClient);
317
318     // If the loading is not started or an error occurs, return an empty result.
319     if (!m_rawData || m_errorCode)
320         return m_stringResult;
321
322     // If already converted from the raw data, return the result now.
323     if (m_isRawDataConverted)
324         return m_stringResult;
325
326     switch (m_readType) {
327     case ReadAsArrayBuffer:
328         // No conversion is needed.
329         break;
330     case ReadAsBinaryString:
331         m_stringResult = m_rawData->toString();
332         m_isRawDataConverted = true;
333         break;
334     case ReadAsText:
335         convertToText();
336         break;
337     case ReadAsDataURL:
338         // Partial data is not supported when reading as data URL.
339         if (m_finishedLoading)
340             convertToDataURL();
341         break;
342     default:
343         ASSERT_NOT_REACHED();
344     }
345
346     return m_stringResult;
347 }
348
349 void FileReaderLoader::convertToText()
350 {
351     m_isRawDataConverted = true;
352
353     if (!m_bytesLoaded) {
354         m_stringResult = "";
355         return;
356     }
357
358     // Decode the data.
359     // The File API spec says that we should use the supplied encoding if it is valid. However, we choose to ignore this
360     // requirement in order to be consistent with how WebKit decodes the web content: always has the BOM override the
361     // provided encoding.
362     // FIXME: consider supporting incremental decoding to improve the perf.
363     StringBuilder builder;
364     if (!m_decoder)
365         m_decoder = TextResourceDecoder::create("text/plain", m_encoding.isValid() ? m_encoding : UTF8Encoding());
366     builder.append(m_decoder->decode(static_cast<const char*>(m_rawData->data()), m_rawData->byteLength()));
367
368     if (m_finishedLoading)
369         builder.append(m_decoder->flush());
370
371     m_stringResult = builder.toString();
372 }
373
374 void FileReaderLoader::convertToDataURL()
375 {
376     m_isRawDataConverted = true;
377
378     StringBuilder builder;
379     builder.append("data:");
380
381     if (!m_bytesLoaded) {
382         m_stringResult = builder.toString();
383         return;
384     }
385
386     builder.append(m_dataType);
387     builder.append(";base64,");
388
389     Vector<char> out;
390     base64Encode(static_cast<const char*>(m_rawData->data()), m_rawData->byteLength(), out);
391     out.append('\0');
392     builder.append(out.data());
393
394     m_stringResult = builder.toString();
395 }
396
397 void FileReaderLoader::setEncoding(const String& encoding)
398 {
399     if (!encoding.isEmpty())
400         m_encoding = WTF::TextEncoding(encoding);
401 }
402
403 } // namespace WebCore