Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / renderer / resources / extensions / file_system_provider_custom_bindings.js
blob8befb1a86b71f81aa366f94805585dd0dd6e95b7
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.
5 // Custom binding for the fileSystemProvider API.
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;
14 /**
15  * Maximum size of the thumbnail in bytes.
16  * @type {number}
17  * @const
18  */
19 var METADATA_THUMBNAIL_SIZE_LIMIT = 32 * 1024 * 1024;
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');
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;
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;
52   return METADATA_THUMBNAIL_FORMAT.test(uri);
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;
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]);
96 eventBindings.registerArgumentMassager(
97     'fileSystemProvider.onUnmountRequested',
98     massageArgumentsDefault);
100 eventBindings.registerArgumentMassager(
101     'fileSystemProvider.onGetMetadataRequested',
102     function(args, dispatch) {
103       var executionStart = Date.now();
104       var options = args[0];
105       var onSuccessCallback = function(metadata) {
106         var error;
107         // It is invalid to return a thumbnail when it's not requested. The
108         // restriction is added in order to avoid fetching the thumbnail while
109         // it's not needed.
110         if (!options.thumbnail && metadata.thumbnail)
111           error = 'Thumbnail data provided, but not requested.';
113         // Check the format and size. Note, that in the C++ layer, there is
114         // another sanity check to avoid passing any evil URL.
115         if ('thumbnail' in metadata && !verifyImageURI(metadata.thumbnail))
116           error = 'Thumbnail format invalid.';
118         if ('thumbnail' in metadata &&
119             metadata.thumbnail.length > METADATA_THUMBNAIL_SIZE_LIMIT) {
120           error = 'Thumbnail data too large.';
121         }
123         if (error) {
124           console.error(error);
125           fileSystemProviderInternal.operationRequestedError(
126               options.fileSystemId, options.requestId, 'FAILED',
127               Date.now() - executionStart);
128           return;
129         }
131         fileSystemProviderInternal.getMetadataRequestedSuccess(
132             options.fileSystemId,
133             options.requestId,
134             annotateMetadata(metadata),
135             Date.now() - executionStart);
136       };
138       var onErrorCallback = function(error) {
139         fileSystemProviderInternal.operationRequestedError(
140             options.fileSystemId, options.requestId, error,
141             Date.now() - executionStart);
142       }
144       dispatch([options, onSuccessCallback, onErrorCallback]);
145     });
147 eventBindings.registerArgumentMassager(
148     'fileSystemProvider.onGetActionsRequested',
149     function(args, dispatch) {
150       var executionStart = Date.now();
151       var options = args[0];
152       var onSuccessCallback = function(actions) {
153         fileSystemProviderInternal.getActionsRequestedSuccess(
154             options.fileSystemId,
155             options.requestId,
156             actions,
157             Date.now() - executionStart);
158       };
160       var onErrorCallback = function(error) {
161         fileSystemProviderInternal.operationRequestedError(
162             options.fileSystemId, options.requestId, error,
163             Date.now() - executionStart);
164       }
166       dispatch([options, onSuccessCallback, onErrorCallback]);
167     });
169 eventBindings.registerArgumentMassager(
170     'fileSystemProvider.onReadDirectoryRequested',
171     function(args, dispatch) {
172       var executionStart = Date.now();
173       var options = args[0];
174       var onSuccessCallback = function(entries, hasNext) {
175         var annotatedEntries = entries.map(annotateMetadata);
176         // It is invalid to return a thumbnail when it's not requested.
177         var error;
178         annotatedEntries.forEach(function(metadata) {
179           if (metadata.thumbnail) {
180             var error =
181                 'Thumbnails must not be provided when reading a directory.';
182             return;
183           }
184         });
186         if (error) {
187           console.error(error);
188           fileSystemProviderInternal.operationRequestedError(
189               options.fileSystemId, options.requestId, 'FAILED',
190               Date.now() - executionStart);
191           return;
192         }
194         fileSystemProviderInternal.readDirectoryRequestedSuccess(
195             options.fileSystemId, options.requestId, annotatedEntries, hasNext,
196             Date.now() - executionStart);
197       };
199       var onErrorCallback = function(error) {
200         fileSystemProviderInternal.operationRequestedError(
201             options.fileSystemId, options.requestId, error,
202             Date.now() - executionStart);
203       }
204       dispatch([options, onSuccessCallback, onErrorCallback]);
205     });
207 eventBindings.registerArgumentMassager(
208     'fileSystemProvider.onOpenFileRequested',
209     massageArgumentsDefault);
211 eventBindings.registerArgumentMassager(
212     'fileSystemProvider.onCloseFileRequested',
213     massageArgumentsDefault);
215 eventBindings.registerArgumentMassager(
216     'fileSystemProvider.onReadFileRequested',
217     function(args, dispatch) {
218       var executionStart = Date.now();
219       var options = args[0];
220       var onSuccessCallback = function(data, hasNext) {
221         fileSystemProviderInternal.readFileRequestedSuccess(
222             options.fileSystemId, options.requestId, data, hasNext,
223             Date.now() - executionStart);
224       };
225       var onErrorCallback = function(error) {
226         fileSystemProviderInternal.operationRequestedError(
227             options.fileSystemId, options.requestId, error,
228             Date.now() - executionStart);
229       }
230       dispatch([options, onSuccessCallback, onErrorCallback]);
231     });
233 eventBindings.registerArgumentMassager(
234     'fileSystemProvider.onCreateDirectoryRequested',
235     massageArgumentsDefault);
237 eventBindings.registerArgumentMassager(
238     'fileSystemProvider.onDeleteEntryRequested',
239     massageArgumentsDefault);
241 eventBindings.registerArgumentMassager(
242     'fileSystemProvider.onCreateFileRequested',
243     massageArgumentsDefault);
245 eventBindings.registerArgumentMassager(
246     'fileSystemProvider.onCopyEntryRequested',
247     massageArgumentsDefault);
249 eventBindings.registerArgumentMassager(
250     'fileSystemProvider.onMoveEntryRequested',
251     massageArgumentsDefault);
253 eventBindings.registerArgumentMassager(
254     'fileSystemProvider.onTruncateRequested',
255     massageArgumentsDefault);
257 eventBindings.registerArgumentMassager(
258     'fileSystemProvider.onWriteFileRequested',
259     massageArgumentsDefault);
261 eventBindings.registerArgumentMassager(
262     'fileSystemProvider.onAbortRequested',
263     massageArgumentsDefault);
265 eventBindings.registerArgumentMassager(
266     'fileSystemProvider.onObserveDirectoryRequested',
267     massageArgumentsDefault);
269 eventBindings.registerArgumentMassager(
270     'fileSystemProvider.onUnobserveEntryRequested',
271     massageArgumentsDefault);
273 eventBindings.registerArgumentMassager(
274     'fileSystemProvider.onAddWatcherRequested',
275     massageArgumentsDefault);
277 eventBindings.registerArgumentMassager(
278     'fileSystemProvider.onRemoveWatcherRequested',
279     massageArgumentsDefault);
281 eventBindings.registerArgumentMassager(
282     'fileSystemProvider.onConfigureRequested',
283     massageArgumentsDefault);
285 eventBindings.registerArgumentMassager(
286     'fileSystemProvider.onExecuteActionRequested',
287     massageArgumentsDefault);
289 eventBindings.registerArgumentMassager(
290     'fileSystemProvider.onMountRequested',
291     function(args, dispatch) {
292       var onSuccessCallback = function() {
293         // TODO(mtomasz): To be implemented.
294       };
295       var onErrorCallback = function(error) {
296         // TODO(mtomasz): To be implemented.
297       }
298       dispatch([onSuccessCallback, onErrorCallback]);
299     });
301 exports.binding = binding.generate();