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