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;
15 * Maximum size of the thumbnail in bytes.
19 var METADATA_THUMBNAIL_SIZE_LIMIT = 32 * 1024 * 1024;
22 * Regular expression to validate if the thumbnail URI is a valid data URI,
23 * taking into account allowed formats.
27 var METADATA_THUMBNAIL_FORMAT = new RegExp(
28 '^data:image/(png|jpeg|webp);', 'i');
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.
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();
43 * Verifies if the passed image URI is valid.
44 * @param {*} uri Image URI.
45 * @return {boolean} True if valid, valse otherwise.
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))
52 return METADATA_THUMBNAIL_FORMAT.test(uri);
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.
61 function annotateMetadata(metadata) {
63 isDirectory: metadata.isDirectory,
66 modificationTime: annotateDate(metadata.modificationTime)
68 if ('mimeType' in metadata)
69 result.mimeType = metadata.mimeType;
70 if ('thumbnail' in metadata)
71 result.thumbnail = metadata.thumbnail;
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
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);
88 var onErrorCallback = function(error) {
89 fileSystemProviderInternal.operationRequestedError(
90 options.fileSystemId, options.requestId, error,
91 Date.now() - executionStart);
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) {
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
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.';
124 console.error(error);
125 fileSystemProviderInternal.operationRequestedError(
126 options.fileSystemId, options.requestId, 'FAILED',
127 Date.now() - executionStart);
131 fileSystemProviderInternal.getMetadataRequestedSuccess(
132 options.fileSystemId,
134 annotateMetadata(metadata),
135 Date.now() - executionStart);
138 var onErrorCallback = function(error) {
139 fileSystemProviderInternal.operationRequestedError(
140 options.fileSystemId, options.requestId, error,
141 Date.now() - executionStart);
144 dispatch([options, onSuccessCallback, onErrorCallback]);
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,
157 Date.now() - executionStart);
160 var onErrorCallback = function(error) {
161 fileSystemProviderInternal.operationRequestedError(
162 options.fileSystemId, options.requestId, error,
163 Date.now() - executionStart);
166 dispatch([options, onSuccessCallback, onErrorCallback]);
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.
178 annotatedEntries.forEach(function(metadata) {
179 if (metadata.thumbnail) {
181 'Thumbnails must not be provided when reading a directory.';
187 console.error(error);
188 fileSystemProviderInternal.operationRequestedError(
189 options.fileSystemId, options.requestId, 'FAILED',
190 Date.now() - executionStart);
194 fileSystemProviderInternal.readDirectoryRequestedSuccess(
195 options.fileSystemId, options.requestId, annotatedEntries, hasNext,
196 Date.now() - executionStart);
199 var onErrorCallback = function(error) {
200 fileSystemProviderInternal.operationRequestedError(
201 options.fileSystemId, options.requestId, error,
202 Date.now() - executionStart);
204 dispatch([options, onSuccessCallback, onErrorCallback]);
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);
225 var onErrorCallback = function(error) {
226 fileSystemProviderInternal.operationRequestedError(
227 options.fileSystemId, options.requestId, error,
228 Date.now() - executionStart);
230 dispatch([options, onSuccessCallback, onErrorCallback]);
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.
295 var onErrorCallback = function(error) {
296 // TODO(mtomasz): To be implemented.
298 dispatch([onSuccessCallback, onErrorCallback]);
301 exports.binding = binding.generate();