OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/child/fileapi/webfilesystem_impl.h" | 5 #include "content/child/fileapi/webfilesystem_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/logging.h" | |
9 #include "base/message_loop/message_loop_proxy.h" | |
8 #include "content/child/child_thread.h" | 10 #include "content/child/child_thread.h" |
9 #include "content/child/fileapi/file_system_dispatcher.h" | 11 #include "content/child/fileapi/file_system_dispatcher.h" |
10 #include "content/child/fileapi/webfilesystem_callback_adapters.h" | 12 #include "content/child/fileapi/webfilesystem_callback_adapters.h" |
11 #include "content/child/fileapi/webfilewriter_impl.h" | 13 #include "content/child/fileapi/webfilewriter_impl.h" |
12 #include "third_party/WebKit/public/web/WebFileSystemCallbacks.h" | 14 #include "content/child/thread_safe_sender.h" |
15 #include "content/common/fileapi/file_system_messages.h" | |
13 #include "third_party/WebKit/public/platform/WebFileInfo.h" | 16 #include "third_party/WebKit/public/platform/WebFileInfo.h" |
14 #include "third_party/WebKit/public/platform/WebString.h" | 17 #include "third_party/WebKit/public/platform/WebString.h" |
15 #include "third_party/WebKit/public/platform/WebURL.h" | 18 #include "third_party/WebKit/public/platform/WebURL.h" |
19 #include "third_party/WebKit/public/web/WebFileSystemCallbacks.h" | |
20 #include "url/gurl.h" | |
21 #include "webkit/child/worker_task_runner.h" | |
16 #include "webkit/glue/webkit_glue.h" | 22 #include "webkit/glue/webkit_glue.h" |
17 | 23 |
18 using WebKit::WebFileInfo; | 24 using WebKit::WebFileInfo; |
19 using WebKit::WebFileSystemCallbacks; | 25 using WebKit::WebFileSystemCallbacks; |
20 using WebKit::WebFileSystemEntry; | 26 using WebKit::WebFileSystemEntry; |
21 using WebKit::WebString; | 27 using WebKit::WebString; |
22 using WebKit::WebURL; | 28 using WebKit::WebURL; |
23 using WebKit::WebVector; | 29 using WebKit::WebVector; |
30 using webkit_glue::WorkerTaskRunner; | |
24 | 31 |
25 namespace content { | 32 namespace content { |
26 | 33 |
27 namespace { | 34 namespace { |
28 | 35 |
29 void DidReadMetadataForCreateFileWriter( | 36 void DidReadMetadataForCreateFileWriter( |
30 const GURL& path, | 37 const GURL& path, |
31 WebKit::WebFileWriterClient* client, | 38 WebKit::WebFileWriterClient* client, |
32 WebKit::WebFileSystemCallbacks* callbacks, | 39 WebKit::WebFileSystemCallbacks* callbacks, |
33 const base::PlatformFileInfo& file_info) { | 40 const base::PlatformFileInfo& file_info) { |
34 if (file_info.is_directory || file_info.size < 0) { | 41 if (file_info.is_directory || file_info.size < 0) { |
35 callbacks->didFail(WebKit::WebFileErrorInvalidState); | 42 callbacks->didFail(WebKit::WebFileErrorInvalidState); |
36 return; | 43 return; |
37 } | 44 } |
38 callbacks->didCreateFileWriter(new WebFileWriterImpl(path, client), | 45 callbacks->didCreateFileWriter(new WebFileWriterImpl(path, client), |
39 file_info.size); | 46 file_info.size); |
40 } | 47 } |
41 | 48 |
49 int CurrentWorkerId() { | |
50 return WorkerTaskRunner::Instance()->CurrentWorkerId(); | |
51 } | |
52 | |
53 class CallbacksWrapper | |
54 : public WebFileSystemCallbacks, | |
55 public WorkerTaskRunner::Observer { | |
56 public: | |
57 CallbacksWrapper(WebFileSystemCallbacks* original_callbacks, | |
58 ThreadSafeSender* thread_safe_sender) | |
59 : callbacks_(original_callbacks), | |
60 thread_safe_sender_(thread_safe_sender), | |
61 worker_id_(CurrentWorkerId()) { | |
62 if (worker_id_) | |
63 WorkerTaskRunner::Instance()->AddStopObserver(this); | |
64 } | |
65 | |
66 virtual ~CallbacksWrapper() { | |
67 if (CurrentWorkerId()) | |
68 WorkerTaskRunner::Instance()->RemoveStopObserver(this); | |
69 } | |
70 | |
71 // WorkerTaskRunner::Observer overrides. | |
72 virtual void OnWorkerRunLoopStopped() OVERRIDE { | |
73 callbacks_->didFail(WebKit::WebFileErrorAbort); | |
74 callbacks_ = NULL; | |
75 } | |
76 | |
77 // WebFileSystemCallbacks overrides. | |
78 virtual void didSucceed() OVERRIDE { | |
79 RunCallback(base::Bind(&WebFileSystemCallbacks::didSucceed, | |
80 base::Unretained(callbacks_))); | |
81 } | |
82 virtual void didReadMetadata(const WebFileInfo& info) OVERRIDE { | |
83 RunCallback(base::Bind(&WebFileSystemCallbacks::didReadMetadata, | |
84 base::Unretained(callbacks_), info)); | |
85 } | |
86 virtual void didReadDirectory(const WebVector<WebFileSystemEntry>& entries, | |
87 bool hasMore) OVERRIDE { | |
88 RunCallback(base::Bind(&WebFileSystemCallbacks::didReadDirectory, | |
89 base::Unretained(callbacks_), entries, hasMore)); | |
90 } | |
91 virtual void didOpenFileSystem(const WebString& name, | |
92 const WebURL& rootURL) OVERRIDE { | |
93 RunCallback(base::Bind(&WebFileSystemCallbacks::didOpenFileSystem, | |
94 base::Unretained(callbacks_), name, rootURL)); | |
95 } | |
96 virtual void didFail(WebKit::WebFileError error) OVERRIDE { | |
97 RunCallback(base::Bind(&WebFileSystemCallbacks::didFail, | |
98 base::Unretained(callbacks_), error)); | |
99 } | |
100 virtual bool shouldBlockUntilCompletion() const OVERRIDE { | |
101 return callbacks_->shouldBlockUntilCompletion(); | |
102 } | |
103 | |
104 void DidCreateSnapshotFile(const base::PlatformFileInfo& file_info, | |
105 const base::FilePath& platform_path, | |
106 int request_id) { | |
107 if (worker_id_ != CurrentWorkerId()) { | |
108 PostTaskToWorker( | |
109 base::Bind(&CallbacksWrapper::DidCreateSnapshotFile, | |
110 base::Unretained(this), file_info, platform_path, | |
111 request_id)); | |
112 return; | |
113 } | |
114 scoped_ptr<CallbacksWrapper> deleter(this); | |
115 DCHECK(callbacks_); | |
116 WebFileInfo web_file_info; | |
117 webkit_glue::PlatformFileInfoToWebFileInfo(file_info, &web_file_info); | |
118 web_file_info.platformPath = platform_path.AsUTF16Unsafe(); | |
119 callbacks_->didCreateSnapshotFile(web_file_info); | |
120 | |
121 thread_safe_sender_->Send( | |
122 new FileSystemHostMsg_DidReceiveSnapshotFile(request_id)); | |
michaeln
2013/07/24 22:21:12
Drat, I think i gave you a bum steer, very sorry :
kinuko
2013/07/25 04:32:41
Yup... I vaguely remember that's how I decided to
| |
123 } | |
124 | |
125 private: | |
126 void RunCallback(const base::Closure& callback) { | |
127 if (worker_id_ != CurrentWorkerId()) { | |
128 PostTaskToWorker(base::Bind(&CallbacksWrapper::RunCallback, | |
129 base::Unretained(this), callback)); | |
130 return; | |
131 } | |
132 scoped_ptr<CallbacksWrapper> deleter(this); | |
133 DCHECK(callbacks_); | |
134 callback.Run(); | |
135 } | |
136 | |
137 void PostTaskToWorker(const base::Closure& closure) { | |
138 if (!WorkerTaskRunner::Instance()->PostTask(worker_id_, closure)) | |
139 delete this; | |
michaeln
2013/07/24 22:21:12
I'm really not sure about 'delete this' correctnes
kinuko
2013/07/25 04:32:41
Right. I overlooked PostTask returns false when Wo
michaeln
2013/07/25 21:39:08
For a process shutdown leaks, who cares, but these
kinuko
2013/07/26 12:29:55
My initial implementation was exactlly following I
| |
140 } | |
141 | |
142 WebFileSystemCallbacks* callbacks_; | |
143 scoped_refptr<ThreadSafeSender> thread_safe_sender_; | |
144 int worker_id_; | |
145 }; | |
146 | |
147 template <typename Method, typename Params> | |
148 void CallDispatcherOnMainThread( | |
149 base::MessageLoopProxy* loop, | |
150 Method method, const Params& params, | |
151 WebFileSystemCallbacks* callbacks) { | |
152 if (!loop->RunsTasksOnCurrentThread()) { | |
153 loop->PostTask(FROM_HERE, | |
154 base::Bind(&CallDispatcherOnMainThread<Method, Params>, | |
155 make_scoped_refptr(loop), | |
156 method, params, callbacks)); | |
157 return; | |
158 } | |
159 if (!ChildThread::current() || | |
160 !ChildThread::current()->file_system_dispatcher()) { | |
161 callbacks->didFail(WebKit::WebFileErrorAbort); | |
162 return; | |
163 } | |
164 DispatchToMethod(ChildThread::current()->file_system_dispatcher(), | |
165 method, params); | |
166 } | |
167 | |
42 } // namespace | 168 } // namespace |
43 | 169 |
44 WebFileSystemImpl::WebFileSystemImpl() { | 170 WebFileSystemImpl::WebFileSystemImpl( |
45 } | 171 base::MessageLoopProxy* main_thread_loop, |
46 | 172 ThreadSafeSender* sender) |
47 void WebFileSystemImpl::move(const WebURL& src_path, | 173 : main_thread_loop_(main_thread_loop), |
48 const WebURL& dest_path, | 174 sender_(sender) { |
49 WebFileSystemCallbacks* callbacks) { | 175 // TODO(kinuko): Support creating and accessing WebFileSystemImpl on |
50 FileSystemDispatcher* dispatcher = | 176 // non-main thread. (crbug.com/257349) |
51 ChildThread::current()->file_system_dispatcher(); | 177 DCHECK(main_thread_loop_->RunsTasksOnCurrentThread()); |
52 dispatcher->Move(GURL(src_path), | 178 } |
53 GURL(dest_path), | 179 |
54 base::Bind(&FileStatusCallbackAdapter, callbacks)); | 180 WebFileSystemImpl::~WebFileSystemImpl() { |
55 } | 181 } |
56 | 182 |
57 void WebFileSystemImpl::copy(const WebURL& src_path, | 183 // WebFileSystem implementation. |
58 const WebURL& dest_path, | 184 void WebFileSystemImpl::move( |
59 WebFileSystemCallbacks* callbacks) { | 185 const WebKit::WebURL& src_path, |
60 FileSystemDispatcher* dispatcher = | 186 const WebKit::WebURL& dest_path, |
61 ChildThread::current()->file_system_dispatcher(); | 187 WebKit::WebFileSystemCallbacks* callbacks) { |
62 dispatcher->Copy(GURL(src_path), | 188 CallbacksWrapper* wrapper = new CallbacksWrapper(callbacks, sender_.get()); |
63 GURL(dest_path), | 189 CallDispatcherOnMainThread( |
64 base::Bind(&FileStatusCallbackAdapter, callbacks)); | 190 main_thread_loop_.get(), |
65 } | 191 &FileSystemDispatcher::Move, |
66 | 192 MakeTuple(GURL(src_path), GURL(dest_path), |
67 void WebFileSystemImpl::remove(const WebURL& path, | 193 base::Bind(&FileStatusCallbackAdapter, wrapper)), |
68 WebFileSystemCallbacks* callbacks) { | 194 wrapper); |
69 FileSystemDispatcher* dispatcher = | 195 } |
70 ChildThread::current()->file_system_dispatcher(); | 196 |
71 dispatcher->Remove( | 197 void WebFileSystemImpl::copy( |
72 GURL(path), | 198 const WebKit::WebURL& src_path, |
73 false /* recursive */, | 199 const WebKit::WebURL& dest_path, |
74 base::Bind(&FileStatusCallbackAdapter, callbacks)); | 200 WebKit::WebFileSystemCallbacks* callbacks) { |
75 } | 201 CallbacksWrapper* wrapper = new CallbacksWrapper(callbacks, sender_.get()); |
76 | 202 CallDispatcherOnMainThread( |
77 void WebFileSystemImpl::removeRecursively(const WebURL& path, | 203 main_thread_loop_.get(), |
78 WebFileSystemCallbacks* callbacks) { | 204 &FileSystemDispatcher::Copy, |
79 FileSystemDispatcher* dispatcher = | 205 MakeTuple(GURL(src_path), GURL(dest_path), |
80 ChildThread::current()->file_system_dispatcher(); | 206 base::Bind(&FileStatusCallbackAdapter, wrapper)), |
81 dispatcher->Remove( | 207 wrapper); |
82 GURL(path), | 208 } |
83 true /* recursive */, | 209 |
84 base::Bind(&FileStatusCallbackAdapter, callbacks)); | 210 void WebFileSystemImpl::remove( |
85 } | 211 const WebKit::WebURL& path, |
86 | 212 WebKit::WebFileSystemCallbacks* callbacks) { |
87 void WebFileSystemImpl::readMetadata(const WebURL& path, | 213 CallbacksWrapper* wrapper = new CallbacksWrapper(callbacks, sender_.get()); |
88 WebFileSystemCallbacks* callbacks) { | 214 CallDispatcherOnMainThread( |
89 FileSystemDispatcher* dispatcher = | 215 main_thread_loop_.get(), |
90 ChildThread::current()->file_system_dispatcher(); | 216 &FileSystemDispatcher::Remove, |
91 dispatcher->ReadMetadata( | 217 MakeTuple(GURL(path), false /* recursive */, |
92 GURL(path), | 218 base::Bind(&FileStatusCallbackAdapter, wrapper)), |
93 base::Bind(&ReadMetadataCallbackAdapter, callbacks), | 219 wrapper); |
94 base::Bind(&FileStatusCallbackAdapter, callbacks)); | 220 } |
95 } | 221 |
96 | 222 void WebFileSystemImpl::removeRecursively( |
97 void WebFileSystemImpl::createFile(const WebURL& path, | 223 const WebKit::WebURL& path, |
98 bool exclusive, | 224 WebKit::WebFileSystemCallbacks* callbacks) { |
99 WebFileSystemCallbacks* callbacks) { | 225 CallbacksWrapper* wrapper = new CallbacksWrapper(callbacks, sender_.get()); |
100 FileSystemDispatcher* dispatcher = | 226 CallDispatcherOnMainThread( |
101 ChildThread::current()->file_system_dispatcher(); | 227 main_thread_loop_.get(), |
102 dispatcher->CreateFile( | 228 &FileSystemDispatcher::Remove, |
103 GURL(path), exclusive, | 229 MakeTuple(GURL(path), true /* recursive */, |
104 base::Bind(&FileStatusCallbackAdapter, callbacks)); | 230 base::Bind(&FileStatusCallbackAdapter, wrapper)), |
105 } | 231 wrapper); |
106 | 232 } |
107 void WebFileSystemImpl::createDirectory(const WebURL& path, | 233 |
108 bool exclusive, | 234 void WebFileSystemImpl::readMetadata( |
109 WebFileSystemCallbacks* callbacks) { | 235 const WebKit::WebURL& path, |
110 FileSystemDispatcher* dispatcher = | 236 WebKit::WebFileSystemCallbacks* callbacks) { |
111 ChildThread::current()->file_system_dispatcher(); | 237 CallbacksWrapper* wrapper = new CallbacksWrapper(callbacks, sender_.get()); |
112 dispatcher->CreateDirectory( | 238 CallDispatcherOnMainThread( |
113 GURL(path), exclusive, false /* recursive */, | 239 main_thread_loop_.get(), |
114 base::Bind(&FileStatusCallbackAdapter, callbacks)); | 240 &FileSystemDispatcher::ReadMetadata, |
115 } | 241 MakeTuple(GURL(path), |
116 | 242 base::Bind(&ReadMetadataCallbackAdapter, wrapper), |
117 void WebFileSystemImpl::fileExists(const WebURL& path, | 243 base::Bind(&FileStatusCallbackAdapter, wrapper)), |
118 WebFileSystemCallbacks* callbacks) { | 244 wrapper); |
119 FileSystemDispatcher* dispatcher = | 245 } |
120 ChildThread::current()->file_system_dispatcher(); | 246 |
121 dispatcher->Exists( | 247 void WebFileSystemImpl::createFile( |
122 GURL(path), false /* directory */, | 248 const WebKit::WebURL& path, |
123 base::Bind(&FileStatusCallbackAdapter, callbacks)); | 249 bool exclusive, |
124 } | 250 WebKit::WebFileSystemCallbacks* callbacks) { |
125 | 251 CallbacksWrapper* wrapper = new CallbacksWrapper(callbacks, sender_.get()); |
126 void WebFileSystemImpl::directoryExists(const WebURL& path, | 252 CallDispatcherOnMainThread( |
127 WebFileSystemCallbacks* callbacks) { | 253 main_thread_loop_.get(), |
128 FileSystemDispatcher* dispatcher = | 254 &FileSystemDispatcher::CreateFile, |
129 ChildThread::current()->file_system_dispatcher(); | 255 MakeTuple(GURL(path), exclusive, |
130 dispatcher->Exists( | 256 base::Bind(&FileStatusCallbackAdapter, wrapper)), |
131 GURL(path), true /* directory */, | 257 wrapper); |
132 base::Bind(&FileStatusCallbackAdapter, callbacks)); | 258 } |
133 } | 259 |
134 | 260 void WebFileSystemImpl::createDirectory( |
135 void WebFileSystemImpl::readDirectory(const WebURL& path, | 261 const WebKit::WebURL& path, |
136 WebFileSystemCallbacks* callbacks) { | 262 bool exclusive, |
137 FileSystemDispatcher* dispatcher = | 263 WebKit::WebFileSystemCallbacks* callbacks) { |
138 ChildThread::current()->file_system_dispatcher(); | 264 CallbacksWrapper* wrapper = new CallbacksWrapper(callbacks, sender_.get()); |
139 dispatcher->ReadDirectory( | 265 CallDispatcherOnMainThread( |
140 GURL(path), | 266 main_thread_loop_.get(), |
141 base::Bind(&ReadDirectoryCallbackAdapater, callbacks), | 267 &FileSystemDispatcher::CreateDirectory, |
142 base::Bind(&FileStatusCallbackAdapter, callbacks)); | 268 MakeTuple(GURL(path), exclusive, false /* recursive */, |
269 base::Bind(&FileStatusCallbackAdapter, wrapper)), | |
270 wrapper); | |
271 } | |
272 | |
273 void WebFileSystemImpl::fileExists( | |
274 const WebKit::WebURL& path, | |
275 WebKit::WebFileSystemCallbacks* callbacks) { | |
276 CallbacksWrapper* wrapper = new CallbacksWrapper(callbacks, sender_.get()); | |
277 CallDispatcherOnMainThread( | |
278 main_thread_loop_.get(), | |
279 &FileSystemDispatcher::Exists, | |
280 MakeTuple(GURL(path), false /* directory */, | |
281 base::Bind(&FileStatusCallbackAdapter, wrapper)), | |
282 wrapper); | |
283 } | |
284 | |
285 void WebFileSystemImpl::directoryExists( | |
286 const WebKit::WebURL& path, | |
287 WebKit::WebFileSystemCallbacks* callbacks) { | |
288 CallbacksWrapper* wrapper = new CallbacksWrapper(callbacks, sender_.get()); | |
289 CallDispatcherOnMainThread( | |
290 main_thread_loop_.get(), | |
291 &FileSystemDispatcher::Exists, | |
292 MakeTuple(GURL(path), true /* directory */, | |
293 base::Bind(&FileStatusCallbackAdapter, wrapper)), | |
294 wrapper); | |
295 } | |
296 | |
297 void WebFileSystemImpl::readDirectory( | |
298 const WebKit::WebURL& path, | |
299 WebKit::WebFileSystemCallbacks* callbacks) { | |
300 CallbacksWrapper* wrapper = new CallbacksWrapper(callbacks, sender_.get()); | |
301 CallDispatcherOnMainThread( | |
302 main_thread_loop_.get(), | |
303 &FileSystemDispatcher::ReadDirectory, | |
304 MakeTuple(GURL(path), | |
305 base::Bind(&ReadDirectoryCallbackAdapater, wrapper), | |
306 base::Bind(&FileStatusCallbackAdapter, wrapper)), | |
307 wrapper); | |
143 } | 308 } |
144 | 309 |
145 WebKit::WebFileWriter* WebFileSystemImpl::createFileWriter( | 310 WebKit::WebFileWriter* WebFileSystemImpl::createFileWriter( |
146 const WebURL& path, WebKit::WebFileWriterClient* client) { | 311 const WebURL& path, WebKit::WebFileWriterClient* client) { |
147 return new WebFileWriterImpl(GURL(path), client); | 312 return new WebFileWriterImpl(GURL(path), client); |
148 } | 313 } |
149 | 314 |
150 void WebFileSystemImpl::createFileWriter( | 315 void WebFileSystemImpl::createFileWriter( |
151 const WebURL& path, | 316 const WebURL& path, |
152 WebKit::WebFileWriterClient* client, | 317 WebKit::WebFileWriterClient* client, |
153 WebKit::WebFileSystemCallbacks* callbacks) { | 318 WebKit::WebFileSystemCallbacks* callbacks) { |
319 // TODO(kinuko): Convert this method to use bridge model. (crbug.com/257349) | |
320 DCHECK(main_thread_loop_->RunsTasksOnCurrentThread()); | |
154 FileSystemDispatcher* dispatcher = | 321 FileSystemDispatcher* dispatcher = |
155 ChildThread::current()->file_system_dispatcher(); | 322 ChildThread::current()->file_system_dispatcher(); |
156 dispatcher->ReadMetadata( | 323 dispatcher->ReadMetadata( |
157 GURL(path), | 324 GURL(path), |
158 base::Bind(&DidReadMetadataForCreateFileWriter, | 325 base::Bind(&DidReadMetadataForCreateFileWriter, |
159 GURL(path), client, callbacks), | 326 GURL(path), client, callbacks), |
160 base::Bind(&FileStatusCallbackAdapter, callbacks)); | 327 base::Bind(&FileStatusCallbackAdapter, callbacks)); |
161 } | 328 } |
162 | 329 |
163 void WebFileSystemImpl::createSnapshotFileAndReadMetadata( | 330 void WebFileSystemImpl::createSnapshotFileAndReadMetadata( |
164 const WebKit::WebURL& path, | 331 const WebKit::WebURL& path, |
165 WebKit::WebFileSystemCallbacks* callbacks) { | 332 WebKit::WebFileSystemCallbacks* callbacks) { |
166 FileSystemDispatcher* dispatcher = | 333 CallbacksWrapper* wrapper = new CallbacksWrapper(callbacks, sender_.get()); |
167 ChildThread::current()->file_system_dispatcher(); | 334 CallDispatcherOnMainThread( |
168 dispatcher->CreateSnapshotFile( | 335 main_thread_loop_.get(), |
169 GURL(path), | 336 &FileSystemDispatcher::CreateSnapshotFile, |
170 base::Bind(&CreateSnapshotFileCallbackAdapter, callbacks), | 337 MakeTuple(GURL(path), |
171 base::Bind(&FileStatusCallbackAdapter, callbacks)); | 338 base::Bind(&CallbacksWrapper::DidCreateSnapshotFile, |
339 base::Unretained(wrapper)), | |
340 base::Bind(&FileStatusCallbackAdapter, wrapper)), | |
341 wrapper); | |
172 } | 342 } |
173 | 343 |
174 } // namespace content | 344 } // namespace content |
OLD | NEW |