Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / filesystem / InspectorFileSystemAgent.cpp
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
88     static CallbackDispatcher* create(PassRefPtr<Handler> handler, HandlingMethod handlingMethod)
89     {
90         return new CallbackDispatcher(handler, handlingMethod);
91     }
92
93     virtual void handleEvent(Argument argument) OVERRIDE
94     {
95         (m_handler.get()->*m_handlingMethod)(argument);
96     }
97
98 private:
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>
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:
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:
128     bool didHitError(FileError* error)
129     {
130         reportResult(error->code());
131         return true;
132     }
133
134     bool didGetEntry(Entry*);
135
136     void reportResult(FileError::ErrorCode errorCode, PassRefPtr<TypeBuilder::FileSystem::Entry> entry = nullptr)
137     {
138         m_requestCallback->sendSuccess(static_cast<int>(errorCode), entry);
139     }
140
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
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
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:
185     static PassRefPtr<DirectoryContentRequest> create(PassRefPtrWillBeRawPtr<RequestDirectoryContentCallback> requestCallback, const String& url)
186     {
187         return adoptRef(new DirectoryContentRequest(requestCallback, url));
188     }
189
190     ~DirectoryContentRequest()
191     {
192         reportResult(FileError::ABORT_ERR);
193     }
194
195     void start(ExecutionContext*);
196
197 private:
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
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
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
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
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
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
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:
306     static PassRefPtr<MetadataRequest> create(PassRefPtrWillBeRawPtr<RequestMetadataCallback> requestCallback, const String& url)
307     {
308         return adoptRef(new MetadataRequest(requestCallback, url));
309     }
310
311     ~MetadataRequest()
312     {
313         reportResult(FileError::ABORT_ERR);
314     }
315
316     void start(ExecutionContext*);
317
318 private:
319     bool didHitError(FileError* error)
320     {
321         reportResult(error->code());
322         return true;
323     }
324
325     bool didGetEntry(Entry*);
326     bool didGetMetadata(Metadata*);
327
328     void reportResult(FileError::ErrorCode errorCode, PassRefPtr<TypeBuilder::FileSystem::Metadata> metadata = nullptr)
329     {
330         m_requestCallback->sendSuccess(static_cast<int>(errorCode), metadata);
331     }
332
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
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
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
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:
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
384     virtual ~FileContentRequest()
385     {
386         reportResult(FileError::ABORT_ERR);
387     }
388
389     void start(ExecutionContext*);
390
391     virtual bool operator==(const EventListener& other) OVERRIDE
392     {
393         return this == &other;
394     }
395
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:
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
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
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
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
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
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
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:
502     static PassRefPtr<DeleteEntryRequest> create(PassRefPtrWillBeRawPtr<DeleteEntryCallback> requestCallback, const KURL& url)
503     {
504         return adoptRef(new DeleteEntryRequest(requestCallback, url));
505     }
506
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:
518         explicit VoidCallbackImpl(PassRefPtr<DeleteEntryRequest> handler)
519             : m_handler(handler)
520         {
521         }
522
523         virtual void handleEvent() OVERRIDE
524         {
525             m_handler->didDeleteEntry();
526         }
527
528     private:
529         RefPtr<DeleteEntryRequest> m_handler;
530     };
531
532     bool didHitError(FileError* error)
533     {
534         reportResult(error->code());
535         return true;
536     }
537
538     bool didGetEntry(Entry*);
539     bool didDeleteEntry();
540
541     void reportResult(FileError::ErrorCode errorCode)
542     {
543         m_requestCallback->sendSuccess(static_cast<int>(errorCode));
544     }
545
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
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
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
591 bool DeleteEntryRequest::didDeleteEntry()
592 {
593     reportResult(static_cast<FileError::ErrorCode>(0));
594     return true;
595 }
596
597 } // anonymous namespace
598
599 // static
600 PassOwnPtrWillBeRawPtr<InspectorFileSystemAgent> InspectorFileSystemAgent::create(Page* page)
601 {
602     return adoptPtrWillBeNoop(new InspectorFileSystemAgent(page));
603 }
604
605 InspectorFileSystemAgent::~InspectorFileSystemAgent()
606 {
607 }
608
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
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
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
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
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
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
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
689 void InspectorFileSystemAgent::clearFrontend()
690 {
691     m_enabled = false;
692     m_state->setBoolean(FileSystemAgentState::fileSystemAgentEnabled, m_enabled);
693 }
694
695 void InspectorFileSystemAgent::restore()
696 {
697     m_enabled = m_state->getBoolean(FileSystemAgentState::fileSystemAgentEnabled);
698 }
699
700 InspectorFileSystemAgent::InspectorFileSystemAgent(Page* page)
701     : InspectorBaseAgent<InspectorFileSystemAgent>("FileSystem")
702     , m_page(page)
703     , m_enabled(false)
704 {
705     ASSERT(m_page);
706 }
707
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
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
731 void InspectorFileSystemAgent::trace(Visitor* visitor)
732 {
733     visitor->trace(m_page);
734     InspectorBaseAgent::trace(visitor);
735 }
736
737 } // namespace blink