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]);
97 eventBindings.registerArgumentMassager(
98 'fileSystemProvider.onUnmountRequested',
99 massageArgumentsDefault);
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) {
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
111 if (!options.thumbnail && metadata.thumbnail)
112 error = 'Thumbnail data provided, but not requested.';
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.';
119 if ('thumbnail' in metadata &&
120 metadata.thumbnail.length > METADATA_THUMBNAIL_SIZE_LIMIT) {
121 error = 'Thumbnail data too large.';
125 console.error(error);
126 fileSystemProviderInternal.operationRequestedError(
127 options.fileSystemId, options.requestId, 'FAILED',
128 Date.now() - executionStart);
132 fileSystemProviderInternal.getMetadataRequestedSuccess(
133 options.fileSystemId,
135 annotateMetadata(metadata),
136 Date.now() - executionStart);
139 var onErrorCallback = function(error) {
140 fileSystemProviderInternal.operationRequestedError(
141 options.fileSystemId, options.requestId, error,
142 Date.now() - executionStart);
145 dispatch([options, onSuccessCallback, onErrorCallback]);
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.
157 annotatedEntries.forEach(function(metadata) {
158 if (metadata.thumbnail) {
160 'Thumbnails must not be provided when reading a directory.';
166 console.error(error);
167 fileSystemProviderInternal.operationRequestedError(
168 options.fileSystemId, options.requestId, 'FAILED',
169 Date.now() - executionStart);
173 fileSystemProviderInternal.readDirectoryRequestedSuccess(
174 options.fileSystemId, options.requestId, annotatedEntries, hasNext,
175 Date.now() - executionStart);
178 var onErrorCallback = function(error) {
179 fileSystemProviderInternal.operationRequestedError(
180 options.fileSystemId, options.requestId, error,
181 Date.now() - executionStart);
183 dispatch([options, onSuccessCallback, onErrorCallback]);
186 eventBindings.registerArgumentMassager(
187 'fileSystemProvider.onOpenFileRequested',
188 massageArgumentsDefault);
190 eventBindings.registerArgumentMassager(
191 'fileSystemProvider.onCloseFileRequested',
192 massageArgumentsDefault);
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);
204 var onErrorCallback = function(error) {
205 fileSystemProviderInternal.operationRequestedError(
206 options.fileSystemId, options.requestId, error,
207 Date.now() - executionStart);
209 dispatch([options, onSuccessCallback, onErrorCallback]);
212 eventBindings.registerArgumentMassager(
213 'fileSystemProvider.onCreateDirectoryRequested',
214 massageArgumentsDefault);
216 eventBindings.registerArgumentMassager(
217 'fileSystemProvider.onDeleteEntryRequested',
218 massageArgumentsDefault);
220 eventBindings.registerArgumentMassager(
221 'fileSystemProvider.onCreateFileRequested',
222 massageArgumentsDefault);
224 eventBindings.registerArgumentMassager(
225 'fileSystemProvider.onCopyEntryRequested',
226 massageArgumentsDefault);
228 eventBindings.registerArgumentMassager(
229 'fileSystemProvider.onMoveEntryRequested',
230 massageArgumentsDefault);
232 eventBindings.registerArgumentMassager(
233 'fileSystemProvider.onTruncateRequested',
234 massageArgumentsDefault);
236 eventBindings.registerArgumentMassager(
237 'fileSystemProvider.onWriteFileRequested',
238 massageArgumentsDefault);
240 eventBindings.registerArgumentMassager(
241 'fileSystemProvider.onAbortRequested',
242 massageArgumentsDefault);
244 eventBindings.registerArgumentMassager(
245 'fileSystemProvider.onObserveDirectoryRequested',
246 massageArgumentsDefault);
248 eventBindings.registerArgumentMassager(
249 'fileSystemProvider.onUnobserveEntryRequested',
250 massageArgumentsDefault);
252 eventBindings.registerArgumentMassager(
253 'fileSystemProvider.onAddWatcherRequested',
254 massageArgumentsDefault);
256 eventBindings.registerArgumentMassager(
257 'fileSystemProvider.onRemoveWatcherRequested',
258 massageArgumentsDefault);
260 exports.binding = binding.generate();