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