Home | History | Annotate | Download | only in filesystem
      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
    738