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