Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / renderer / resources / extensions / file_system_provider_custom_bindings.js
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Custom binding for the fileSystemProvider API.
6
7 var binding = require('binding').Binding.create('fileSystemProvider');
8 var fileSystemProviderInternal =
9     require('binding').Binding.create('fileSystemProviderInternal').generate();
10 var eventBindings = require('event_bindings');
11 var fileSystemNatives = requireNative('file_system_natives');
12 var GetDOMError = fileSystemNatives.GetDOMError;
13
14 /**
15  * Maximum size of the thumbnail in bytes.
16  * @type {number}
17  * @const
18  */
19 var METADATA_THUMBNAIL_SIZE_LIMIT = 32 * 1024 * 1024;
20
21 /**
22  * Regular expression to validate if the thumbnail URI is a valid data URI,
23  * taking into account allowed formats.
24  * @type {RegExp}
25  * @const
26  */
27 var METADATA_THUMBNAIL_FORMAT = new RegExp(
28     '^data:image/(png|jpeg|webp);', 'i');
29
30 /**
31  * Annotates a date with its serialized value.
32  * @param {Date} date Input date.
33  * @return {Date} Date with an extra <code>value</code> attribute.
34  */
35 function annotateDate(date) {
36   // Copy in case the input date is frozen.
37   var result = new Date(date.getTime());
38   result.value = result.toString();
39   return result;
40 }
41
42 /**
43  * Verifies if the passed image URI is valid.
44  * @param {*} uri Image URI.
45  * @return {boolean} True if valid, valse otherwise.
46  */
47 function verifyImageURI(uri) {
48   // The URI is specified by a user, so the type may be incorrect.
49   if (typeof uri != 'string' && !(uri instanceof String))
50     return false;
51
52   return METADATA_THUMBNAIL_FORMAT.test(uri);
53 }
54
55 /**
56  * Annotates an entry metadata by serializing its modifiedTime value.
57  * @param {EntryMetadata} metadata Input metadata.
58  * @return {EntryMetadata} metadata Annotated metadata, which can be passed
59  *     back to the C++ layer.
60  */
61 function annotateMetadata(metadata) {
62   var result = {
63     isDirectory: metadata.isDirectory,
64     name: metadata.name,
65     size: metadata.size,
66     modificationTime: annotateDate(metadata.modificationTime)
67   };
68   if ('mimeType' in metadata)
69     result.mimeType = metadata.mimeType;
70   if ('thumbnail' in metadata)
71     result.thumbnail = metadata.thumbnail;
72   return result;
73 }
74
75 /**
76  * Massages arguments of an event raised by the File System Provider API.
77  * @param {Array.<*>} args Input arguments.
78  * @param {function(Array.<*>)} dispatch Closure to be called with massaged
79  *     arguments.
80  */
81 function massageArgumentsDefault(args, dispatch) {
82   var executionStart = Date.now();
83   var options = args[0];
84   var onSuccessCallback = function(hasNext) {
85     fileSystemProviderInternal.operationRequestedSuccess(
86         options.fileSystemId, options.requestId, Date.now() - executionStart);
87   };
88   var onErrorCallback = function(error) {
89     fileSystemProviderInternal.operationRequestedError(
90         options.fileSystemId, options.requestId, error,
91         Date.now() - executionStart);
92   }
93   dispatch([options, onSuccessCallback, onErrorCallback]);
94 }
95
96
97 eventBindings.registerArgumentMassager(
98     'fileSystemProvider.onUnmountRequested',
99     massageArgumentsDefault);
100
101 eventBindings.registerArgumentMassager(
102     'fileSystemProvider.onGetMetadataRequested',
103     function(args, dispatch) {
104       var executionStart = Date.now();
105       var options = args[0];
106       var onSuccessCallback = function(metadata) {
107         var error;
108         // It is invalid to return a thumbnail when it's not requested. The
109         // restriction is added in order to avoid fetching the thumbnail while
110         // it's not needed.
111         if (!options.thumbnail && metadata.thumbnail)
112           error = 'Thumbnail data provided, but not requested.';
113
114         // Check the format and size. Note, that in the C++ layer, there is
115         // another sanity check to avoid passing any evil URL.
116         if ('thumbnail' in metadata && !verifyImageURI(metadata.thumbnail))
117           error = 'Thumbnail format invalid.';
118
119         if ('thumbnail' in metadata &&
120             metadata.thumbnail.length > METADATA_THUMBNAIL_SIZE_LIMIT) {
121           error = 'Thumbnail data too large.';
122         }
123
124         if (error) {
125           console.error(error);
126           fileSystemProviderInternal.operationRequestedError(
127               options.fileSystemId, options.requestId, 'FAILED',
128               Date.now() - executionStart);
129           return;
130         }
131
132         fileSystemProviderInternal.getMetadataRequestedSuccess(
133             options.fileSystemId,
134             options.requestId,
135             annotateMetadata(metadata),
136             Date.now() - executionStart);
137       };
138
139       var onErrorCallback = function(error) {
140         fileSystemProviderInternal.operationRequestedError(
141             options.fileSystemId, options.requestId, error,
142             Date.now() - executionStart);
143       }
144
145       dispatch([options, onSuccessCallback, onErrorCallback]);
146     });
147
148 eventBindings.registerArgumentMassager(
149     'fileSystemProvider.onReadDirectoryRequested',
150     function(args, dispatch) {
151       var executionStart = Date.now();
152       var options = args[0];
153       var onSuccessCallback = function(entries, hasNext) {
154         var annotatedEntries = entries.map(annotateMetadata);
155         // It is invalid to return a thumbnail when it's not requested.
156         var error;
157         annotatedEntries.forEach(function(metadata) {
158           if (metadata.thumbnail) {
159             var error =
160                 'Thumbnails must not be provided when reading a directory.';
161             return;
162           }
163         });
164
165         if (error) {
166           console.error(error);
167           fileSystemProviderInternal.operationRequestedError(
168               options.fileSystemId, options.requestId, 'FAILED',
169               Date.now() - executionStart);
170           return;
171         }
172
173         fileSystemProviderInternal.readDirectoryRequestedSuccess(
174             options.fileSystemId, options.requestId, annotatedEntries, hasNext,
175             Date.now() - executionStart);
176       };
177
178       var onErrorCallback = function(error) {
179         fileSystemProviderInternal.operationRequestedError(
180             options.fileSystemId, options.requestId, error,
181             Date.now() - executionStart);
182       }
183       dispatch([options, onSuccessCallback, onErrorCallback]);
184     });
185
186 eventBindings.registerArgumentMassager(
187     'fileSystemProvider.onOpenFileRequested',
188     massageArgumentsDefault);
189
190 eventBindings.registerArgumentMassager(
191     'fileSystemProvider.onCloseFileRequested',
192     massageArgumentsDefault);
193
194 eventBindings.registerArgumentMassager(
195     'fileSystemProvider.onReadFileRequested',
196     function(args, dispatch) {
197       var executionStart = Date.now();
198       var options = args[0];
199       var onSuccessCallback = function(data, hasNext) {
200         fileSystemProviderInternal.readFileRequestedSuccess(
201             options.fileSystemId, options.requestId, data, hasNext,
202             Date.now() - executionStart);
203       };
204       var onErrorCallback = function(error) {
205         fileSystemProviderInternal.operationRequestedError(
206             options.fileSystemId, options.requestId, error,
207             Date.now() - executionStart);
208       }
209       dispatch([options, onSuccessCallback, onErrorCallback]);
210     });
211
212 eventBindings.registerArgumentMassager(
213     'fileSystemProvider.onCreateDirectoryRequested',
214     massageArgumentsDefault);
215
216 eventBindings.registerArgumentMassager(
217     'fileSystemProvider.onDeleteEntryRequested',
218     massageArgumentsDefault);
219
220 eventBindings.registerArgumentMassager(
221     'fileSystemProvider.onCreateFileRequested',
222     massageArgumentsDefault);
223
224 eventBindings.registerArgumentMassager(
225     'fileSystemProvider.onCopyEntryRequested',
226     massageArgumentsDefault);
227
228 eventBindings.registerArgumentMassager(
229     'fileSystemProvider.onMoveEntryRequested',
230     massageArgumentsDefault);
231
232 eventBindings.registerArgumentMassager(
233     'fileSystemProvider.onTruncateRequested',
234     massageArgumentsDefault);
235
236 eventBindings.registerArgumentMassager(
237     'fileSystemProvider.onWriteFileRequested',
238     massageArgumentsDefault);
239
240 eventBindings.registerArgumentMassager(
241     'fileSystemProvider.onAbortRequested',
242     massageArgumentsDefault);
243
244 eventBindings.registerArgumentMassager(
245     'fileSystemProvider.onObserveDirectoryRequested',
246     massageArgumentsDefault);
247
248 eventBindings.registerArgumentMassager(
249     'fileSystemProvider.onUnobserveEntryRequested',
250     massageArgumentsDefault);
251
252 eventBindings.registerArgumentMassager(
253     'fileSystemProvider.onAddWatcherRequested',
254     massageArgumentsDefault);
255
256 eventBindings.registerArgumentMassager(
257     'fileSystemProvider.onRemoveWatcherRequested',
258     massageArgumentsDefault);
259
260 exports.binding = binding.generate();