Web Inspector: Add requestFileContent command and fileContentReceived event
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 2 Jul 2012 14:12:04 +0000 (14:12 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 2 Jul 2012 14:12:04 +0000 (14:12 +0000)
https://bugs.webkit.org/show_bug.cgi?id=89642

Patch by Taiju Tsuiki <tzik@chromium.org> on 2012-07-02
Reviewed by Vsevolod Vlasov.

Source/WebCore:

Test: http/tests/inspector/filesystem/read-file.html

* inspector/Inspector.json:
* inspector/InspectorFileSystemAgent.cpp:
(WebCore):
(WebCore::InspectorFileSystemAgent::requestFileContent):
* inspector/InspectorFileSystemAgent.h:
(InspectorFileSystemAgent):
* inspector/front-end/FileSystemModel.js:
(WebInspector.FileSystemModel.prototype.requestMetadata):
(WebInspector.FileSystemModel.prototype.requestFileContent):
(WebInspector.FileSystemModel.File.prototype.get resourceType):
(WebInspector.FileSystemModel.File.prototype.requestFileContent):
(WebInspector.FileSystemRequestManager):
(WebInspector.FileSystemRequestManager.prototype._metadataReceived):
(WebInspector.FileSystemRequestManager.prototype.requestFileContent.requestAccepted):
(WebInspector.FileSystemRequestManager.prototype.requestFileContent):
(WebInspector.FileSystemRequestManager.prototype._fileContentReceived):
(WebInspector.FileSystemDispatcher.prototype.metadataReceived):
(WebInspector.FileSystemDispatcher.prototype.fileContentReceived):

LayoutTests:

* http/tests/inspector/filesystem/read-file-expected.txt: Added.
* http/tests/inspector/filesystem/read-file.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@121676 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/http/tests/inspector/filesystem/read-file-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/inspector/filesystem/read-file.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/inspector/Inspector.json
Source/WebCore/inspector/InspectorFileSystemAgent.cpp
Source/WebCore/inspector/InspectorFileSystemAgent.h
Source/WebCore/inspector/front-end/FileSystemModel.js

index c5c73a8..58f5920 100644 (file)
@@ -1,5 +1,15 @@
 2012-07-02  Taiju Tsuiki  <tzik@chromium.org>
 
+        Web Inspector: Add requestFileContent command and fileContentReceived event
+        https://bugs.webkit.org/show_bug.cgi?id=89642
+
+        Reviewed by Vsevolod Vlasov.
+
+        * http/tests/inspector/filesystem/read-file-expected.txt: Added.
+        * http/tests/inspector/filesystem/read-file.html: Added.
+
+2012-07-02  Taiju Tsuiki  <tzik@chromium.org>
+
         Web Inspector: Add refresh button to FileSystemView status bar
         https://bugs.webkit.org/show_bug.cgi?id=90244
 
diff --git a/LayoutTests/http/tests/inspector/filesystem/read-file-expected.txt b/LayoutTests/http/tests/inspector/filesystem/read-file-expected.txt
new file mode 100644 (file)
index 0000000..0389774
--- /dev/null
@@ -0,0 +1,5 @@
+Tests readFile.
+
+errorCode = 0
+content = "UEFTUw==" [PASS]
+
diff --git a/LayoutTests/http/tests/inspector/filesystem/read-file.html b/LayoutTests/http/tests/inspector/filesystem/read-file.html
new file mode 100644 (file)
index 0000000..34341d8
--- /dev/null
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script src="../inspector-test.js"></script>
+<script src="filesystem-test.js"></script>
+<script>
+document.addEventListener("DOMContentLoaded", runTest);
+function test()
+{
+    var requestManager = new WebInspector.FileSystemRequestManager();
+    InspectorTest.clearFileSystem(step1);
+
+    function step1()
+    {
+        InspectorTest.createDirectory("/hoge", step2);
+    }
+
+    function step2()
+    {
+        InspectorTest.writeFile("/hoge/fuga", "piPASSyo", step3);
+    }
+
+    function step3()
+    {
+        requestManager.requestFileContent("filesystem:http://127.0.0.1:8000/temporary/hoge/fuga", 2, 6, step4);
+    }
+
+    function step4(errorCode, content)
+    {
+        InspectorTest.addResult("errorCode = " + errorCode);
+        if (content)
+            InspectorTest.addResult("content = \"" + content + "\" [" + atob(content) + "]");
+        else
+            InspectorTest.addResult("content = (null)");
+
+        InspectorTest.clearFileSystem(step5);
+    }
+
+    function step5()
+    {
+        InspectorTest.completeTest();
+    }
+}
+</script>
+</head>
+<body>
+<p>Tests readFile.</p>
+</body>
+</html>
index 5232c11..850c7c0 100644 (file)
@@ -1,5 +1,33 @@
 2012-07-02  Taiju Tsuiki  <tzik@chromium.org>
 
+        Web Inspector: Add requestFileContent command and fileContentReceived event
+        https://bugs.webkit.org/show_bug.cgi?id=89642
+
+        Reviewed by Vsevolod Vlasov.
+
+        Test: http/tests/inspector/filesystem/read-file.html
+
+        * inspector/Inspector.json:
+        * inspector/InspectorFileSystemAgent.cpp:
+        (WebCore):
+        (WebCore::InspectorFileSystemAgent::requestFileContent):
+        * inspector/InspectorFileSystemAgent.h:
+        (InspectorFileSystemAgent):
+        * inspector/front-end/FileSystemModel.js:
+        (WebInspector.FileSystemModel.prototype.requestMetadata):
+        (WebInspector.FileSystemModel.prototype.requestFileContent):
+        (WebInspector.FileSystemModel.File.prototype.get resourceType):
+        (WebInspector.FileSystemModel.File.prototype.requestFileContent):
+        (WebInspector.FileSystemRequestManager):
+        (WebInspector.FileSystemRequestManager.prototype._metadataReceived):
+        (WebInspector.FileSystemRequestManager.prototype.requestFileContent.requestAccepted):
+        (WebInspector.FileSystemRequestManager.prototype.requestFileContent):
+        (WebInspector.FileSystemRequestManager.prototype._fileContentReceived):
+        (WebInspector.FileSystemDispatcher.prototype.metadataReceived):
+        (WebInspector.FileSystemDispatcher.prototype.fileContentReceived):
+
+2012-07-02  Taiju Tsuiki  <tzik@chromium.org>
+
         Web Inspector: Add refresh button to FileSystemView status bar
         https://bugs.webkit.org/show_bug.cgi?id=90244
 
index 851606e..3711cf3 100644 (file)
                     { "name": "requestId", "$ref": "RequestId", "description": "Request identifier. Corresponding metadataReceived event should have same requestId with this." }
                 ],
                 "description": "Returns metadata of the entry as metadataReceived event."
+            },
+            {
+                "name": "requestFileContent",
+                "parameters": [
+                    { "name": "url", "type": "string", "description": "URL of the file that the frontend is requesting to read from." },
+                    { "name": "start", "type": "integer", "optional": true, "description": "Specifies the start of range to read." },
+                    { "name": "end", "type": "integer", "optional": true, "description": "Specifies the end of range to read exclusively." }
+                ],
+                "returns": [
+                    { "name": "requestId", "$ref": "RequestId", "description": "Request identifier. Corresponding fileContentReceived event should have same requestId with this." }
+                ],
+                "description": "Returns content of the file as fileContentReceived event. Result should be sliced into [start, end)."
             }
         ],
         "events": [
             {
                 "name": "metadataReceived",
                 "parameters": [
-                    { "name": "requestId", "type": "integer", "description": "Request Identifier that was returned in response to the corresponding getMetadata request." },
+                    { "name": "requestId", "type": "integer", "description": "Request Identifier that was returned in response to the corresponding requestMetadata command." },
                     { "name": "errorCode", "type": "integer", "description": "0, if no error. Otherwise, errorCode is set to FileError::ErrorCode value." },
                     { "name": "metadata", "$ref": "FileSystem.Metadata", "optional": true, "description": "Contains metadata of the entry if the command completed successfully." }
                 ],
-                "description": "Completion event of getMetadata command."
+                "description": "Completion event of requestMetadata command."
+            },
+            {
+                "name": "fileContentReceived",
+                "parameters": [
+                    { "name": "requestId", "type": "integer", "description": "Request Identifier that was returned in response to the corresponding requestFileContent command." },
+                    { "name": "errorCode", "type": "integer", "description": "0, if no error. Otherwise, errorCode is set to FileError::ErrorCode value." },
+                    { "name": "content", "type": "string", "optional": true, "description": "Contains content of the file as base64 encoded string." }
+                ],
+                "description": "Completion event of requestFileContent command."
             }
         ]
     },
index 06206de..adafeea 100644 (file)
 
 #include "InspectorFileSystemAgent.h"
 
+#include "Base64.h"
 #include "DOMFileSystem.h"
 #include "DirectoryEntry.h"
 #include "DirectoryReader.h"
 #include "Document.h"
 #include "EntriesCallback.h"
+#include "Entry.h"
 #include "EntryArray.h"
 #include "EntryCallback.h"
 #include "ErrorCallback.h"
+#include "FileCallback.h"
+#include "FileEntry.h"
 #include "FileError.h"
+#include "FileReader.h"
 #include "FileSystemCallback.h"
 #include "FileSystemCallbacks.h"
 #include "Frame.h"
@@ -54,6 +59,7 @@
 #include "MIMETypeRegistry.h"
 #include "Metadata.h"
 #include "MetadataCallback.h"
+#include "ScriptExecutionContext.h"
 #include "SecurityOrigin.h"
 
 using WebCore::TypeBuilder::Array;
@@ -400,6 +406,129 @@ bool GetMetadataTask::didGetMetadata(Metadata* metadata)
     return true;
 }
 
+class ReadFileTask : public EventListener {
+    WTF_MAKE_NONCOPYABLE(ReadFileTask);
+public:
+    static PassRefPtr<ReadFileTask> create(PassRefPtr<FrontendProvider> frontendProvider, int requestId, const String& url, long long start, long long end)
+    {
+        return adoptRef(new ReadFileTask(frontendProvider, requestId, url, start, end));
+    }
+
+    virtual ~ReadFileTask()
+    {
+        reportResult(FileError::ABORT_ERR, 0);
+    }
+
+    void start(ScriptExecutionContext*);
+
+
+    virtual bool operator==(const EventListener& other) OVERRIDE
+    {
+        return this == &other;
+    }
+
+    virtual void handleEvent(ScriptExecutionContext*, Event* event) OVERRIDE
+    {
+        if (event->type() == eventNames().loadEvent)
+            didRead();
+        else if (event->type() == eventNames().errorEvent)
+            didHitError(m_reader->error().get());
+    }
+
+private:
+    bool didHitError(FileError* error)
+    {
+        reportResult(error->code(), 0);
+        return true;
+    }
+
+    bool didGetEntry(Entry*);
+    bool didGetFile(File*);
+    void didRead();
+
+    void reportResult(FileError::ErrorCode errorCode, const String* result)
+    {
+        if (!m_frontendProvider || !m_frontendProvider->frontend())
+            return;
+        m_frontendProvider->frontend()->fileContentReceived(m_requestId, static_cast<int>(errorCode), result);
+        m_frontendProvider = 0;
+    }
+
+    ReadFileTask(PassRefPtr<FrontendProvider> frontendProvider, int requestId, const String& url, long long start, long long end)
+        : EventListener(EventListener::CPPEventListenerType)
+        , m_frontendProvider(frontendProvider)
+        , m_requestId(requestId)
+        , m_url(ParsedURLString, url)
+        , m_start(start)
+        , m_end(end)
+        , m_current(start) { }
+
+    RefPtr<FrontendProvider> m_frontendProvider;
+    int m_requestId;
+    KURL m_url;
+    int m_start;
+    long long m_end;
+    long long m_current;
+
+    RefPtr<FileReader> m_reader;
+};
+
+void ReadFileTask::start(ScriptExecutionContext* scriptExecutionContext)
+{
+    ASSERT(scriptExecutionContext);
+
+    FileSystemType type;
+    String path;
+    if (!DOMFileSystemBase::crackFileSystemURL(m_url, type, path)) {
+        reportResult(FileError::SYNTAX_ERR, 0);
+        return;
+    }
+
+    RefPtr<EntryCallback> successCallback = CallbackDispatcherFactory<EntryCallback>::create(this, &ReadFileTask::didGetEntry);
+    RefPtr<ErrorCallback> errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &ReadFileTask::didHitError);
+    OwnPtr<ResolveURICallbacks> fileSystemCallbacks = ResolveURICallbacks::create(successCallback, errorCallback, scriptExecutionContext, type, path);
+
+    LocalFileSystem::localFileSystem().readFileSystem(scriptExecutionContext, type, fileSystemCallbacks.release());
+}
+
+bool ReadFileTask::didGetEntry(Entry* entry)
+{
+    if (entry->isDirectory()) {
+        reportResult(FileError::TYPE_MISMATCH_ERR, 0);
+        return true;
+    }
+
+    if (!entry->filesystem()->scriptExecutionContext()) {
+        reportResult(FileError::ABORT_ERR, 0);
+        return true;
+    }
+
+    RefPtr<FileCallback> successCallback = CallbackDispatcherFactory<FileCallback>::create(this, &ReadFileTask::didGetFile);
+    RefPtr<ErrorCallback> errorCallback = CallbackDispatcherFactory<ErrorCallback>::create(this, &ReadFileTask::didHitError);
+    static_cast<FileEntry*>(entry)->file(successCallback, errorCallback);
+
+    m_reader = FileReader::create(entry->filesystem()->scriptExecutionContext());
+    return true;
+}
+
+bool ReadFileTask::didGetFile(File* file)
+{
+    RefPtr<Blob> blob = file->slice(m_start, m_end);
+    m_reader->setOnload(this);
+    m_reader->setOnerror(this);
+
+    ExceptionCode ec = 0;
+    m_reader->readAsArrayBuffer(blob.get(), ec);
+    return true;
+}
+
+void ReadFileTask::didRead()
+{
+    RefPtr<ArrayBuffer> result = m_reader->arrayBufferResult();
+    String encodedResult = base64Encode(static_cast<char*>(result->data()), result->byteLength());
+    reportResult(static_cast<FileError::ErrorCode>(0), &encodedResult);
+}
+
 }
 
 // static
@@ -478,6 +607,22 @@ void InspectorFileSystemAgent::requestMetadata(ErrorString* error, const String&
         m_frontendProvider->frontend()->metadataReceived(*requestId, static_cast<int>(FileError::ABORT_ERR), 0);
 }
 
+void InspectorFileSystemAgent::requestFileContent(ErrorString* error, const String& url, const int* start, const int* end, int* requestId)
+{
+    if (!m_enabled || !m_frontendProvider) {
+        *error = "FileSystem agent is not enabled";
+        return;
+    }
+    ASSERT(m_frontendProvider->frontend());
+
+    *requestId = m_nextRequestId++;
+
+    if (ScriptExecutionContext* scriptExecutionContext = scriptExecutionContextForOrigin(SecurityOrigin::createFromString(url).get()))
+        ReadFileTask::create(m_frontendProvider, *requestId, url, start ? *start : 0, end ? *end : std::numeric_limits<long long>::max())->start(scriptExecutionContext);
+    else
+        m_frontendProvider->frontend()->fileContentReceived(*requestId, static_cast<int>(FileError::ABORT_ERR), 0);
+}
+
 void InspectorFileSystemAgent::setFrontend(InspectorFrontend* frontend)
 {
     ASSERT(frontend);
index 82f95c4..0e56b38 100644 (file)
@@ -62,6 +62,7 @@ public:
     virtual void requestFileSystemRoot(ErrorString*, const String& origin, const String& type, int* requestId) OVERRIDE;
     virtual void requestDirectoryContent(ErrorString*, const String& url, int* requestId) OVERRIDE;
     virtual void requestMetadata(ErrorString*, const String& url, int* requestId) OVERRIDE;
+    virtual void requestFileContent(ErrorString*, const String& url, const int* start, const int* end, int* requestId) OVERRIDE;
 
     virtual void setFrontend(InspectorFrontend*) OVERRIDE;
     virtual void clearFrontend() OVERRIDE;
index 8ba591f..41939ee 100644 (file)
@@ -237,9 +237,24 @@ WebInspector.FileSystemModel.prototype = {
         callback(errorCode, entries);
     },
 
+    /**
+     * @param {WebInspector.FileSystemModel.Entry} entry
+     * @param {function(number, FileSystemAgent.Metadata=)} callback
+     */
     requestMetadata: function(entry, callback)
     {
         this._agentWrapper.requestMetadata(entry.url, callback);
+    },
+
+    /**
+     * @param {WebInspector.FileSystemModel.File} file
+     * @param {number} start
+     * @param {number} end
+     * @param {function(number, string=)} callback
+     */
+    requestFileContent: function(file, start, end, callback)
+    {
+        this._agentWrapper.requestFileContent(file.url, start, end, callback);
     }
 }
 
@@ -407,6 +422,16 @@ WebInspector.FileSystemModel.File.prototype = {
     get resourceType()
     {
         return this._resourceType;
+    },
+
+    /**
+     * @param {number} start
+     * @param {number} end
+     * @param {function(number, string=)} callback
+     */
+    requestFileContent: function(start, end, callback)
+    {
+        this.fileSystemModel.requestFileContent(this, start, end, callback);
     }
 }
 
@@ -420,6 +445,7 @@ WebInspector.FileSystemRequestManager = function()
     this._pendingFileSystemRootRequests = {};
     this._pendingDirectoryContentRequests = {};
     this._pendingMetadataRequests = {};
+    this._pendingFileContentRequests = {};
 
     InspectorBackend.registerFileSystemDispatcher(new WebInspector.FileSystemDispatcher(this));
     FileSystemAgent.enable();
@@ -510,6 +536,38 @@ WebInspector.FileSystemRequestManager.prototype = {
             return;
         delete this._pendingMetadataRequests[requestId];
         callback(errorCode, metadata);
+    },
+
+    /**
+     * @param {string} url
+     * @param {number} start
+     * @param {number} end
+     * @param {function(number, string)} callback
+     */
+    requestFileContent: function(url, start, end, callback)
+    {
+        var store = this._pendingFileContentRequests;
+        FileSystemAgent.requestFileContent(url, start, end, requestAccepted);
+
+        function requestAccepted(error, requestId)
+        {
+            if (!error)
+                store[requestId] = callback;
+        }
+    },
+
+    /**
+     * @param {number} requestId
+     * @param {number} errorCode
+     * @param {string=} content
+     */
+    _fileContentReceived: function(requestId, errorCode, content)
+    {
+        var callback = /** @type {function(number, string=)} */ this._pendingFileContentRequests[requestId];
+        if (!callback)
+            return;
+        delete this._pendingFileContentRequests[requestId];
+        callback(errorCode, content);
     }
 }
 
@@ -552,5 +610,15 @@ WebInspector.FileSystemDispatcher.prototype = {
     metadataReceived: function(requestId, errorCode, metadata)
     {
         this._agentWrapper._metadataReceived(requestId, errorCode, metadata);
+    },
+
+    /**
+     * @param {number} requestId
+     * @param {number} errorCode
+     * @param {string=} content
+     */
+    fileContentReceived: function(requestId, errorCode, content)
+    {
+        this._agentWrapper._fileContentReceived(requestId, errorCode, content);
     }
 }