1 /*
2 * Copyright (C) 2011, 2012 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 #include "modules/filesystem/InspectorFileSystemAgent.h"
33
34 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
35 #include "core/dom/DOMImplementation.h"
36 #include "core/dom/Document.h"
37 #include "core/events/Event.h"
38 #include "core/fileapi/File.h"
39 #include "core/fileapi/FileError.h"
40 #include "core/fileapi/FileReader.h"
41 #include "core/frame/LocalFrame.h"
42 #include "core/html/VoidCallback.h"
43 #include "core/html/parser/TextResourceDecoder.h"
44 #include "core/inspector/InspectorState.h"
45 #include "core/page/Page.h"
46 #include "modules/filesystem/DOMFileSystem.h"
47 #include "modules/filesystem/DirectoryEntry.h"
48 #include "modules/filesystem/DirectoryReader.h"
49 #include "modules/filesystem/EntriesCallback.h"
50 #include "modules/filesystem/Entry.h"
51 #include "modules/filesystem/EntryCallback.h"
52 #include "modules/filesystem/ErrorCallback.h"
53 #include "modules/filesystem/FileCallback.h"
54 #include "modules/filesystem/FileEntry.h"
55 #include "modules/filesystem/FileSystemCallbacks.h"
56 #include "modules/filesystem/LocalFileSystem.h"
57 #include "modules/filesystem/Metadata.h"
58 #include "modules/filesystem/MetadataCallback.h"
59 #include "platform/MIMETypeRegistry.h"
60 #include "platform/heap/Handle.h"
61 #include "platform/weborigin/KURL.h"
62 #include "platform/weborigin/SecurityOrigin.h"
63 #include "wtf/ArrayBuffer.h"
64 #include "wtf/text/Base64.h"
65 #include "wtf/text/TextEncoding.h"
66
67 using blink::TypeBuilder::Array;
68
69 typedef blink::InspectorBackendDispatcher::FileSystemCommandHandler::RequestFileSystemRootCallback RequestFileSystemRootCallback;
70 typedef blink::InspectorBackendDispatcher::FileSystemCommandHandler::RequestDirectoryContentCallback RequestDirectoryContentCallback;
71 typedef blink::InspectorBackendDispatcher::FileSystemCommandHandler::RequestMetadataCallback RequestMetadataCallback;
72 typedef blink::InspectorBackendDispatcher::FileSystemCommandHandler::RequestFileContentCallback RequestFileContentCallback;
73 typedef blink::InspectorBackendDispatcher::FileSystemCommandHandler::DeleteEntryCallback DeleteEntryCallback;
74
75 namespace blink {
76
77 namespace FileSystemAgentState {
78 static const char fileSystemAgentEnabled[] = "fileSystemAgentEnabled";
79 }
80
81 namespace {
82
83 template<typename BaseCallback, typename Handler, typename Argument>
84 class CallbackDispatcher FINAL : public BaseCallback {
85 public:
86 typedef bool (Handler::*HandlingMethod)(Argument);
87
create(PassRefPtr<Handler> handler,HandlingMethod handlingMethod)88 static CallbackDispatcher* create(PassRefPtr<Handler> handler, HandlingMethod handlingMethod)
89 {
90 return new CallbackDispatcher(handler, handlingMethod);
91 }
92
handleEvent(Argument argument)93 virtual void handleEvent(Argument argument) OVERRIDE
94 {
95 (m_handler.get()->*m_handlingMethod)(argument);
96 }
97
98 private:
CallbackDispatcher(PassRefPtr<Handler> handler,HandlingMethod handlingMethod)99 CallbackDispatcher(PassRefPtr<Handler> handler, HandlingMethod handlingMethod)
100 : m_handler(handler)
101 , m_handlingMethod(handlingMethod) { }
102
103 RefPtr<Handler> m_handler;
104 HandlingMethod m_handlingMethod;
105 };
106
107 template<typename BaseCallback>
108 class CallbackDispatcherFactory {
109 public:
110 template<typename Handler, typename Argument>
create(Handler * handler,bool (Handler::* handlingMethod)(Argument))111 static CallbackDispatcher<BaseCallback, Handler, Argument>* create(Handler* handler, bool (Handler::*handlingMethod)(Argument))
112 {
113 return CallbackDispatcher<BaseCallback, Handler, Argument>::create(PassRefPtr<Handler>(handler), handlingMethod);
114 }
115 };
116
117 class FileSystemRootRequest : public RefCounted<FileSystemRootRequest> {
118 WTF_MAKE_NONCOPYABLE(FileSystemRootRequest);
119 public:
create(PassRefPtrWillBeRawPtr<RequestFileSystemRootCallback> requestCallback,const String & type)120 static PassRefPtr<FileSystemRootRequest> create(PassRefPtrWillBeRawPtr<RequestFileSystemRootCallback> requestCallback, const String& type)
121 {
122 return adoptRef(new FileSystemRootRequest(requestCallback, type));
123 }
124
125 void start(ExecutionContext*);
126
127 private:
didHitError(FileError * error)128 bool didHitError(FileError* error)
129 {
130 reportResult(error->code());
131 return true;
132 }
133
134 bool didGetEntry(Entry*);
135
reportResult(FileError::ErrorCode errorCode,PassRefPtr<TypeBuilder::FileSystem::Entry> entry=nullptr)136 void reportResult(FileError::ErrorCode errorCode, PassRefPtr<TypeBuilder::FileSystem::Entry> entry = nullptr)
137 {
138 m_requestCallback->sendSuccess(static_cast<int>(errorCode), entry);
139 }
140
FileSystemRootRequest(PassRefPtrWillBeRawPtr<RequestFileSystemRootCallback> requestCallback,const String & type)141 FileSystemRootRequest(PassRefPtrWillBeRawPtr<RequestFileSystemRootCallback> requestCallback, const String& type)
142 : m_requestCallback(requestCallback)
143 , m_type(type) { }
144
145 RefPtrWillBePersistent<RequestFileSystemRootCallback> m_requestCallback;
146 String m_type;
147 };
148
start(ExecutionContext * executionContext)149 void FileSystemRootRequest::start(ExecutionContext* executionContext)
150 {
151 ASSERT(executionContext);
152
153 ErrorCallback* errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &FileSystemRootRequest::didHitError);
154
155 FileSystemType type;
156 if (!DOMFileSystemBase::pathPrefixToFileSystemType(m_type, type)) {
157 errorCallback->handleEvent(FileError::create(FileError::SYNTAX_ERR).get());
158 return;
159 }
160
161 KURL rootURL = DOMFileSystemBase::createFileSystemRootURL(executionContext->securityOrigin()->toString(), type);
162 if (!rootURL.isValid()) {
163 errorCallback->handleEvent(FileError::create(FileError::SYNTAX_ERR).get());
164 return;
165 }
166
167 EntryCallback* successCallback = CallbackDispatcherFactory<EntryCallback>::create(this, &FileSystemRootRequest::didGetEntry);
168 OwnPtr<AsyncFileSystemCallbacks> fileSystemCallbacks = ResolveURICallbacks::create(successCallback, errorCallback, executionContext);
169 LocalFileSystem::from(*executionContext)->resolveURL(executionContext, rootURL, fileSystemCallbacks.release());
170 }
171
didGetEntry(Entry * entry)172 bool FileSystemRootRequest::didGetEntry(Entry* entry)
173 {
174 RefPtr<TypeBuilder::FileSystem::Entry> result = TypeBuilder::FileSystem::Entry::create()
175 .setUrl(entry->toURL())
176 .setName("/")
177 .setIsDirectory(true);
178 reportResult(static_cast<FileError::ErrorCode>(0), result);
179 return true;
180 }
181
182 class DirectoryContentRequest FINAL : public RefCounted<DirectoryContentRequest> {
183 WTF_MAKE_NONCOPYABLE(DirectoryContentRequest);
184 public:
create(PassRefPtrWillBeRawPtr<RequestDirectoryContentCallback> requestCallback,const String & url)185 static PassRefPtr<DirectoryContentRequest> create(PassRefPtrWillBeRawPtr<RequestDirectoryContentCallback> requestCallback, const String& url)
186 {
187 return adoptRef(new DirectoryContentRequest(requestCallback, url));
188 }
189
~DirectoryContentRequest()190 ~DirectoryContentRequest()
191 {
192 reportResult(FileError::ABORT_ERR);
193 }
194
195 void start(ExecutionContext*);
196
197 private:
didHitError(FileError * error)198 bool didHitError(FileError* error)
199 {
200 reportResult(error->code());
201 return true;
202 }
203
204 bool didGetEntry(Entry*);
205 bool didReadDirectoryEntries(const EntryHeapVector&);
206
reportResult(FileError::ErrorCode errorCode,PassRefPtr<Array<TypeBuilder::FileSystem::Entry>> entries=nullptr)207 void reportResult(FileError::ErrorCode errorCode, PassRefPtr<Array<TypeBuilder::FileSystem::Entry> > entries = nullptr)
208 {
209 m_requestCallback->sendSuccess(static_cast<int>(errorCode), entries);
210 }
211
DirectoryContentRequest(PassRefPtrWillBeRawPtr<RequestDirectoryContentCallback> requestCallback,const String & url)212 DirectoryContentRequest(PassRefPtrWillBeRawPtr<RequestDirectoryContentCallback> requestCallback, const String& url)
213 : m_requestCallback(requestCallback)
214 , m_url(ParsedURLString, url) { }
215
216 void readDirectoryEntries();
217
218 RefPtrWillBePersistent<RequestDirectoryContentCallback> m_requestCallback;
219 KURL m_url;
220 RefPtr<Array<TypeBuilder::FileSystem::Entry> > m_entries;
221 Persistent<DirectoryReader> m_directoryReader;
222 };
223
start(ExecutionContext * executionContext)224 void DirectoryContentRequest::start(ExecutionContext* executionContext)
225 {
226 ASSERT(executionContext);
227
228 ErrorCallback* errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &DirectoryContentRequest::didHitError);
229 EntryCallback* successCallback = CallbackDispatcherFactory<EntryCallback>::create(this, &DirectoryContentRequest::didGetEntry);
230
231 OwnPtr<AsyncFileSystemCallbacks> fileSystemCallbacks = ResolveURICallbacks::create(successCallback, errorCallback, executionContext);
232
233 LocalFileSystem::from(*executionContext)->resolveURL(executionContext, m_url, fileSystemCallbacks.release());
234 }
235
didGetEntry(Entry * entry)236 bool DirectoryContentRequest::didGetEntry(Entry* entry)
237 {
238 if (!entry->isDirectory()) {
239 reportResult(FileError::TYPE_MISMATCH_ERR);
240 return true;
241 }
242
243 m_directoryReader = toDirectoryEntry(entry)->createReader();
244 m_entries = Array<TypeBuilder::FileSystem::Entry>::create();
245 readDirectoryEntries();
246 return true;
247 }
248
readDirectoryEntries()249 void DirectoryContentRequest::readDirectoryEntries()
250 {
251 if (!m_directoryReader->filesystem()->executionContext()) {
252 reportResult(FileError::ABORT_ERR);
253 return;
254 }
255
256 EntriesCallback* successCallback = CallbackDispatcherFactory<EntriesCallback>::create(this, &DirectoryContentRequest::didReadDirectoryEntries);
257 ErrorCallback* errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &DirectoryContentRequest::didHitError);
258 m_directoryReader->readEntries(successCallback, errorCallback);
259 }
260
didReadDirectoryEntries(const EntryHeapVector & entries)261 bool DirectoryContentRequest::didReadDirectoryEntries(const EntryHeapVector& entries)
262 {
263 if (entries.isEmpty()) {
264 reportResult(static_cast<FileError::ErrorCode>(0), m_entries);
265 return true;
266 }
267
268 for (size_t i = 0; i < entries.size(); ++i) {
269 Entry* entry = entries[i];
270 RefPtr<TypeBuilder::FileSystem::Entry> entryForFrontend = TypeBuilder::FileSystem::Entry::create()
271 .setUrl(entry->toURL())
272 .setName(entry->name())
273 .setIsDirectory(entry->isDirectory());
274
275 using TypeBuilder::Page::ResourceType;
276 if (!entry->isDirectory()) {
277 String mimeType = MIMETypeRegistry::getMIMETypeForPath(entry->name());
278 ResourceType::Enum resourceType;
279 if (MIMETypeRegistry::isSupportedImageMIMEType(mimeType)) {
280 resourceType = ResourceType::Image;
281 entryForFrontend->setIsTextFile(false);
282 } else if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType)) {
283 resourceType = ResourceType::Script;
284 entryForFrontend->setIsTextFile(true);
285 } else if (MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType)) {
286 resourceType = ResourceType::Document;
287 entryForFrontend->setIsTextFile(true);
288 } else {
289 resourceType = ResourceType::Other;
290 entryForFrontend->setIsTextFile(DOMImplementation::isXMLMIMEType(mimeType) || DOMImplementation::isTextMIMEType(mimeType));
291 }
292
293 entryForFrontend->setMimeType(mimeType);
294 entryForFrontend->setResourceType(resourceType);
295 }
296
297 m_entries->addItem(entryForFrontend);
298 }
299 readDirectoryEntries();
300 return true;
301 }
302
303 class MetadataRequest FINAL : public RefCounted<MetadataRequest> {
304 WTF_MAKE_NONCOPYABLE(MetadataRequest);
305 public:
create(PassRefPtrWillBeRawPtr<RequestMetadataCallback> requestCallback,const String & url)306 static PassRefPtr<MetadataRequest> create(PassRefPtrWillBeRawPtr<RequestMetadataCallback> requestCallback, const String& url)
307 {
308 return adoptRef(new MetadataRequest(requestCallback, url));
309 }
310
~MetadataRequest()311 ~MetadataRequest()
312 {
313 reportResult(FileError::ABORT_ERR);
314 }
315
316 void start(ExecutionContext*);
317
318 private:
didHitError(FileError * error)319 bool didHitError(FileError* error)
320 {
321 reportResult(error->code());
322 return true;
323 }
324
325 bool didGetEntry(Entry*);
326 bool didGetMetadata(Metadata*);
327
reportResult(FileError::ErrorCode errorCode,PassRefPtr<TypeBuilder::FileSystem::Metadata> metadata=nullptr)328 void reportResult(FileError::ErrorCode errorCode, PassRefPtr<TypeBuilder::FileSystem::Metadata> metadata = nullptr)
329 {
330 m_requestCallback->sendSuccess(static_cast<int>(errorCode), metadata);
331 }
332
MetadataRequest(PassRefPtrWillBeRawPtr<RequestMetadataCallback> requestCallback,const String & url)333 MetadataRequest(PassRefPtrWillBeRawPtr<RequestMetadataCallback> requestCallback, const String& url)
334 : m_requestCallback(requestCallback)
335 , m_url(ParsedURLString, url) { }
336
337 RefPtrWillBePersistent<RequestMetadataCallback> m_requestCallback;
338 KURL m_url;
339 bool m_isDirectory;
340 };
341
start(ExecutionContext * executionContext)342 void MetadataRequest::start(ExecutionContext* executionContext)
343 {
344 ASSERT(executionContext);
345
346 ErrorCallback* errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &MetadataRequest::didHitError);
347 EntryCallback* successCallback = CallbackDispatcherFactory<EntryCallback>::create(this, &MetadataRequest::didGetEntry);
348 OwnPtr<AsyncFileSystemCallbacks> fileSystemCallbacks = ResolveURICallbacks::create(successCallback, errorCallback, executionContext);
349 LocalFileSystem::from(*executionContext)->resolveURL(executionContext, m_url, fileSystemCallbacks.release());
350 }
351
didGetEntry(Entry * entry)352 bool MetadataRequest::didGetEntry(Entry* entry)
353 {
354 if (!entry->filesystem()->executionContext()) {
355 reportResult(FileError::ABORT_ERR);
356 return true;
357 }
358
359 MetadataCallback* successCallback = CallbackDispatcherFactory<MetadataCallback>::create(this, &MetadataRequest::didGetMetadata);
360 ErrorCallback* errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &MetadataRequest::didHitError);
361 entry->getMetadata(successCallback, errorCallback);
362 m_isDirectory = entry->isDirectory();
363 return true;
364 }
365
didGetMetadata(Metadata * metadata)366 bool MetadataRequest::didGetMetadata(Metadata* metadata)
367 {
368 using TypeBuilder::FileSystem::Metadata;
369 RefPtr<Metadata> result = Metadata::create()
370 .setModificationTime(metadata->modificationTime())
371 .setSize(metadata->size());
372 reportResult(static_cast<FileError::ErrorCode>(0), result);
373 return true;
374 }
375
376 class FileContentRequest FINAL : public EventListener {
377 WTF_MAKE_NONCOPYABLE(FileContentRequest);
378 public:
create(PassRefPtrWillBeRawPtr<RequestFileContentCallback> requestCallback,const String & url,bool readAsText,long long start,long long end,const String & charset)379 static PassRefPtr<FileContentRequest> create(PassRefPtrWillBeRawPtr<RequestFileContentCallback> requestCallback, const String& url, bool readAsText, long long start, long long end, const String& charset)
380 {
381 return adoptRef(new FileContentRequest(requestCallback, url, readAsText, start, end, charset));
382 }
383
~FileContentRequest()384 virtual ~FileContentRequest()
385 {
386 reportResult(FileError::ABORT_ERR);
387 }
388
389 void start(ExecutionContext*);
390
operator ==(const EventListener & other)391 virtual bool operator==(const EventListener& other) OVERRIDE
392 {
393 return this == &other;
394 }
395
handleEvent(ExecutionContext *,Event * event)396 virtual void handleEvent(ExecutionContext*, Event* event) OVERRIDE
397 {
398 if (event->type() == EventTypeNames::load)
399 didRead();
400 else if (event->type() == EventTypeNames::error)
401 didHitError(m_reader->error().get());
402 }
403
404 private:
didHitError(FileError * error)405 bool didHitError(FileError* error)
406 {
407 reportResult(error->code());
408 return true;
409 }
410
411 bool didGetEntry(Entry*);
412 bool didGetFile(File*);
413 void didRead();
414
reportResult(FileError::ErrorCode errorCode,const String * result=0,const String * charset=0)415 void reportResult(FileError::ErrorCode errorCode, const String* result = 0, const String* charset = 0)
416 {
417 m_requestCallback->sendSuccess(static_cast<int>(errorCode), result, charset);
418 }
419
FileContentRequest(PassRefPtrWillBeRawPtr<RequestFileContentCallback> requestCallback,const String & url,bool readAsText,long long start,long long end,const String & charset)420 FileContentRequest(PassRefPtrWillBeRawPtr<RequestFileContentCallback> requestCallback, const String& url, bool readAsText, long long start, long long end, const String& charset)
421 : EventListener(EventListener::CPPEventListenerType)
422 , m_requestCallback(requestCallback)
423 , m_url(ParsedURLString, url)
424 , m_readAsText(readAsText)
425 , m_start(start)
426 , m_end(end)
427 , m_charset(charset) { }
428
429 RefPtrWillBePersistent<RequestFileContentCallback> m_requestCallback;
430 KURL m_url;
431 bool m_readAsText;
432 int m_start;
433 long long m_end;
434 String m_mimeType;
435 String m_charset;
436
437 RefPtrWillBePersistent<FileReader> m_reader;
438 };
439
start(ExecutionContext * executionContext)440 void FileContentRequest::start(ExecutionContext* executionContext)
441 {
442 ASSERT(executionContext);
443
444 ErrorCallback* errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &FileContentRequest::didHitError);
445 EntryCallback* successCallback = CallbackDispatcherFactory<EntryCallback>::create(this, &FileContentRequest::didGetEntry);
446
447 OwnPtr<AsyncFileSystemCallbacks> fileSystemCallbacks = ResolveURICallbacks::create(successCallback, errorCallback, executionContext);
448 LocalFileSystem::from(*executionContext)->resolveURL(executionContext, m_url, fileSystemCallbacks.release());
449 }
450
didGetEntry(Entry * entry)451 bool FileContentRequest::didGetEntry(Entry* entry)
452 {
453 if (entry->isDirectory()) {
454 reportResult(FileError::TYPE_MISMATCH_ERR);
455 return true;
456 }
457
458 if (!entry->filesystem()->executionContext()) {
459 reportResult(FileError::ABORT_ERR);
460 return true;
461 }
462
463 FileCallback* successCallback = CallbackDispatcherFactory<FileCallback>::create(this, &FileContentRequest::didGetFile);
464 ErrorCallback* errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &FileContentRequest::didHitError);
465 toFileEntry(entry)->file(successCallback, errorCallback);
466
467 m_reader = FileReader::create(entry->filesystem()->executionContext());
468 m_mimeType = MIMETypeRegistry::getMIMETypeForPath(entry->name());
469
470 return true;
471 }
472
didGetFile(File * file)473 bool FileContentRequest::didGetFile(File* file)
474 {
475 RefPtrWillBeRawPtr<Blob> blob = static_cast<Blob*>(file)->slice(m_start, m_end, IGNORE_EXCEPTION);
476 m_reader->setOnload(this);
477 m_reader->setOnerror(this);
478
479 m_reader->readAsArrayBuffer(blob.get(), IGNORE_EXCEPTION);
480 return true;
481 }
482
didRead()483 void FileContentRequest::didRead()
484 {
485 RefPtr<ArrayBuffer> buffer = m_reader->arrayBufferResult();
486
487 if (!m_readAsText) {
488 String result = base64Encode(static_cast<char*>(buffer->data()), buffer->byteLength());
489 reportResult(static_cast<FileError::ErrorCode>(0), &result, 0);
490 return;
491 }
492
493 OwnPtr<TextResourceDecoder> decoder = TextResourceDecoder::create(m_mimeType, m_charset, true);
494 String result = decoder->decode(static_cast<char*>(buffer->data()), buffer->byteLength());
495 result = result + decoder->flush();
496 m_charset = decoder->encoding().name();
497 reportResult(static_cast<FileError::ErrorCode>(0), &result, &m_charset);
498 }
499
500 class DeleteEntryRequest FINAL : public RefCounted<DeleteEntryRequest> {
501 public:
create(PassRefPtrWillBeRawPtr<DeleteEntryCallback> requestCallback,const KURL & url)502 static PassRefPtr<DeleteEntryRequest> create(PassRefPtrWillBeRawPtr<DeleteEntryCallback> requestCallback, const KURL& url)
503 {
504 return adoptRef(new DeleteEntryRequest(requestCallback, url));
505 }
506
~DeleteEntryRequest()507 ~DeleteEntryRequest()
508 {
509 reportResult(FileError::ABORT_ERR);
510 }
511
512 void start(ExecutionContext*);
513
514 private:
515 // CallbackDispatcherFactory doesn't handle 0-arg handleEvent methods
516 class VoidCallbackImpl FINAL : public VoidCallback {
517 public:
VoidCallbackImpl(PassRefPtr<DeleteEntryRequest> handler)518 explicit VoidCallbackImpl(PassRefPtr<DeleteEntryRequest> handler)
519 : m_handler(handler)
520 {
521 }
522
handleEvent()523 virtual void handleEvent() OVERRIDE
524 {
525 m_handler->didDeleteEntry();
526 }
527
528 private:
529 RefPtr<DeleteEntryRequest> m_handler;
530 };
531
didHitError(FileError * error)532 bool didHitError(FileError* error)
533 {
534 reportResult(error->code());
535 return true;
536 }
537
538 bool didGetEntry(Entry*);
539 bool didDeleteEntry();
540
reportResult(FileError::ErrorCode errorCode)541 void reportResult(FileError::ErrorCode errorCode)
542 {
543 m_requestCallback->sendSuccess(static_cast<int>(errorCode));
544 }
545
DeleteEntryRequest(PassRefPtrWillBeRawPtr<DeleteEntryCallback> requestCallback,const KURL & url)546 DeleteEntryRequest(PassRefPtrWillBeRawPtr<DeleteEntryCallback> requestCallback, const KURL& url)
547 : m_requestCallback(requestCallback)
548 , m_url(url) { }
549
550 RefPtrWillBePersistent<DeleteEntryCallback> m_requestCallback;
551 KURL m_url;
552 };
553
start(ExecutionContext * executionContext)554 void DeleteEntryRequest::start(ExecutionContext* executionContext)
555 {
556 ASSERT(executionContext);
557
558 ErrorCallback* errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &DeleteEntryRequest::didHitError);
559
560 FileSystemType type;
561 String path;
562 if (!DOMFileSystemBase::crackFileSystemURL(m_url, type, path)) {
563 errorCallback->handleEvent(FileError::create(FileError::SYNTAX_ERR).get());
564 return;
565 }
566
567 if (path == "/") {
568 VoidCallback* successCallback = new VoidCallbackImpl(this);
569 OwnPtr<AsyncFileSystemCallbacks> fileSystemCallbacks = VoidCallbacks::create(successCallback, errorCallback, executionContext, nullptr);
570 LocalFileSystem::from(*executionContext)->deleteFileSystem(executionContext, type, fileSystemCallbacks.release());
571 } else {
572 EntryCallback* successCallback = CallbackDispatcherFactory<EntryCallback>::create(this, &DeleteEntryRequest::didGetEntry);
573 OwnPtr<AsyncFileSystemCallbacks> fileSystemCallbacks = ResolveURICallbacks::create(successCallback, errorCallback, executionContext);
574 LocalFileSystem::from(*executionContext)->resolveURL(executionContext, m_url, fileSystemCallbacks.release());
575 }
576 }
577
didGetEntry(Entry * entry)578 bool DeleteEntryRequest::didGetEntry(Entry* entry)
579 {
580 VoidCallback* successCallback = new VoidCallbackImpl(this);
581 ErrorCallback* errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &DeleteEntryRequest::didHitError);
582 if (entry->isDirectory()) {
583 DirectoryEntry* directoryEntry = toDirectoryEntry(entry);
584 directoryEntry->removeRecursively(successCallback, errorCallback);
585 } else {
586 entry->remove(successCallback, errorCallback);
587 }
588 return true;
589 }
590
didDeleteEntry()591 bool DeleteEntryRequest::didDeleteEntry()
592 {
593 reportResult(static_cast<FileError::ErrorCode>(0));
594 return true;
595 }
596
597 } // anonymous namespace
598
599 // static
create(Page * page)600 PassOwnPtrWillBeRawPtr<InspectorFileSystemAgent> InspectorFileSystemAgent::create(Page* page)
601 {
602 return adoptPtrWillBeNoop(new InspectorFileSystemAgent(page));
603 }
604
~InspectorFileSystemAgent()605 InspectorFileSystemAgent::~InspectorFileSystemAgent()
606 {
607 }
608
enable(ErrorString *)609 void InspectorFileSystemAgent::enable(ErrorString*)
610 {
611 if (m_enabled)
612 return;
613 m_enabled = true;
614 m_state->setBoolean(FileSystemAgentState::fileSystemAgentEnabled, m_enabled);
615 }
616
disable(ErrorString *)617 void InspectorFileSystemAgent::disable(ErrorString*)
618 {
619 if (!m_enabled)
620 return;
621 m_enabled = false;
622 m_state->setBoolean(FileSystemAgentState::fileSystemAgentEnabled, m_enabled);
623 }
624
requestFileSystemRoot(ErrorString * error,const String & origin,const String & type,PassRefPtrWillBeRawPtr<RequestFileSystemRootCallback> requestCallback)625 void InspectorFileSystemAgent::requestFileSystemRoot(ErrorString* error, const String& origin, const String& type, PassRefPtrWillBeRawPtr<RequestFileSystemRootCallback> requestCallback)
626 {
627 if (!assertEnabled(error))
628 return;
629
630 ExecutionContext* executionContext = assertExecutionContextForOrigin(error, SecurityOrigin::createFromString(origin).get());
631 if (!executionContext)
632 return;
633
634 FileSystemRootRequest::create(requestCallback, type)->start(executionContext);
635 }
636
requestDirectoryContent(ErrorString * error,const String & url,PassRefPtrWillBeRawPtr<RequestDirectoryContentCallback> requestCallback)637 void InspectorFileSystemAgent::requestDirectoryContent(ErrorString* error, const String& url, PassRefPtrWillBeRawPtr<RequestDirectoryContentCallback> requestCallback)
638 {
639 if (!assertEnabled(error))
640 return;
641
642 ExecutionContext* executionContext = assertExecutionContextForOrigin(error, SecurityOrigin::createFromString(url).get());
643 if (!executionContext)
644 return;
645
646 DirectoryContentRequest::create(requestCallback, url)->start(executionContext);
647 }
648
requestMetadata(ErrorString * error,const String & url,PassRefPtrWillBeRawPtr<RequestMetadataCallback> requestCallback)649 void InspectorFileSystemAgent::requestMetadata(ErrorString* error, const String& url, PassRefPtrWillBeRawPtr<RequestMetadataCallback> requestCallback)
650 {
651 if (!assertEnabled(error))
652 return;
653
654 ExecutionContext* executionContext = assertExecutionContextForOrigin(error, SecurityOrigin::createFromString(url).get());
655 if (!executionContext)
656 return;
657
658 MetadataRequest::create(requestCallback, url)->start(executionContext);
659 }
660
requestFileContent(ErrorString * error,const String & url,bool readAsText,const int * start,const int * end,const String * charset,PassRefPtrWillBeRawPtr<RequestFileContentCallback> requestCallback)661 void InspectorFileSystemAgent::requestFileContent(ErrorString* error, const String& url, bool readAsText, const int* start, const int* end, const String* charset, PassRefPtrWillBeRawPtr<RequestFileContentCallback> requestCallback)
662 {
663 if (!assertEnabled(error))
664 return;
665
666 ExecutionContext* executionContext = assertExecutionContextForOrigin(error, SecurityOrigin::createFromString(url).get());
667 if (!executionContext)
668 return;
669
670 long long startPosition = start ? *start : 0;
671 long long endPosition = end ? *end : std::numeric_limits<long long>::max();
672 FileContentRequest::create(requestCallback, url, readAsText, startPosition, endPosition, charset ? *charset : "")->start(executionContext);
673 }
674
deleteEntry(ErrorString * error,const String & urlString,PassRefPtrWillBeRawPtr<DeleteEntryCallback> requestCallback)675 void InspectorFileSystemAgent::deleteEntry(ErrorString* error, const String& urlString, PassRefPtrWillBeRawPtr<DeleteEntryCallback> requestCallback)
676 {
677 if (!assertEnabled(error))
678 return;
679
680 KURL url(ParsedURLString, urlString);
681
682 ExecutionContext* executionContext = assertExecutionContextForOrigin(error, SecurityOrigin::create(url).get());
683 if (!executionContext)
684 return;
685
686 DeleteEntryRequest::create(requestCallback, url)->start(executionContext);
687 }
688
clearFrontend()689 void InspectorFileSystemAgent::clearFrontend()
690 {
691 m_enabled = false;
692 m_state->setBoolean(FileSystemAgentState::fileSystemAgentEnabled, m_enabled);
693 }
694
restore()695 void InspectorFileSystemAgent::restore()
696 {
697 m_enabled = m_state->getBoolean(FileSystemAgentState::fileSystemAgentEnabled);
698 }
699
InspectorFileSystemAgent(Page * page)700 InspectorFileSystemAgent::InspectorFileSystemAgent(Page* page)
701 : InspectorBaseAgent<InspectorFileSystemAgent>("FileSystem")
702 , m_page(page)
703 , m_enabled(false)
704 {
705 ASSERT(m_page);
706 }
707
assertEnabled(ErrorString * error)708 bool InspectorFileSystemAgent::assertEnabled(ErrorString* error)
709 {
710 if (!m_enabled) {
711 *error = "FileSystem agent is not enabled.";
712 return false;
713 }
714 return true;
715 }
716
assertExecutionContextForOrigin(ErrorString * error,SecurityOrigin * origin)717 ExecutionContext* InspectorFileSystemAgent::assertExecutionContextForOrigin(ErrorString* error, SecurityOrigin* origin)
718 {
719 for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
720 if (!frame->isLocalFrame())
721 continue;
722 LocalFrame* localFrame = toLocalFrame(frame);
723 if (localFrame->document() && localFrame->document()->securityOrigin()->isSameSchemeHostPort(origin))
724 return localFrame->document();
725 }
726
727 *error = "No frame is available for the request";
728 return 0;
729 }
730
trace(Visitor * visitor)731 void InspectorFileSystemAgent::trace(Visitor* visitor)
732 {
733 visitor->trace(m_page);
734 InspectorBaseAgent::trace(visitor);
735 }
736
737 } // namespace blink
738