1 /*
2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3  * Copyright (C) 2009, 2011 Google Inc. All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  */
27 
28 #include "third_party/blink/renderer/modules/filesystem/worker_global_scope_file_system.h"
29 
30 #include <memory>
31 
32 #include "third_party/blink/public/mojom/filesystem/file_system.mojom-blink.h"
33 #include "third_party/blink/renderer/core/fileapi/file_error.h"
34 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
35 #include "third_party/blink/renderer/modules/filesystem/async_callback_helper.h"
36 #include "third_party/blink/renderer/modules/filesystem/directory_entry_sync.h"
37 #include "third_party/blink/renderer/modules/filesystem/dom_file_system.h"
38 #include "third_party/blink/renderer/modules/filesystem/entry.h"
39 #include "third_party/blink/renderer/modules/filesystem/file_entry_sync.h"
40 #include "third_party/blink/renderer/modules/filesystem/file_system_callbacks.h"
41 #include "third_party/blink/renderer/modules/filesystem/local_file_system.h"
42 #include "third_party/blink/renderer/modules/filesystem/sync_callback_helper.h"
43 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
44 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
45 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
46 
47 namespace blink {
48 
webkitRequestFileSystem(WorkerGlobalScope & worker,int type,int64_t size,V8FileSystemCallback * success_callback,V8ErrorCallback * error_callback)49 void WorkerGlobalScopeFileSystem::webkitRequestFileSystem(
50     WorkerGlobalScope& worker,
51     int type,
52     int64_t size,
53     V8FileSystemCallback* success_callback,
54     V8ErrorCallback* error_callback) {
55   ExecutionContext* secure_context = worker.GetExecutionContext();
56   auto error_callback_wrapper =
57       AsyncCallbackHelper::ErrorCallback(error_callback);
58 
59   if (!secure_context->GetSecurityOrigin()->CanAccessFileSystem()) {
60     DOMFileSystem::ReportError(&worker, std::move(error_callback_wrapper),
61                                base::File::FILE_ERROR_SECURITY);
62     return;
63   } else if (secure_context->GetSecurityOrigin()->IsLocal()) {
64     UseCounter::Count(secure_context, WebFeature::kFileAccessedFileSystem);
65   }
66 
67   mojom::blink::FileSystemType file_system_type =
68       static_cast<mojom::blink::FileSystemType>(type);
69   if (!DOMFileSystemBase::IsValidType(file_system_type)) {
70     DOMFileSystem::ReportError(&worker, std::move(error_callback_wrapper),
71                                base::File::FILE_ERROR_INVALID_OPERATION);
72     return;
73   }
74 
75   auto success_callback_wrapper =
76       AsyncCallbackHelper::SuccessCallback<DOMFileSystem>(success_callback);
77 
78   LocalFileSystem::From(worker)->RequestFileSystem(
79       file_system_type, size,
80       std::make_unique<FileSystemCallbacks>(std::move(success_callback_wrapper),
81                                             std::move(error_callback_wrapper),
82                                             &worker, file_system_type),
83       LocalFileSystem::kAsynchronous);
84 }
85 
webkitRequestFileSystemSync(WorkerGlobalScope & worker,int type,int64_t size,ExceptionState & exception_state)86 DOMFileSystemSync* WorkerGlobalScopeFileSystem::webkitRequestFileSystemSync(
87     WorkerGlobalScope& worker,
88     int type,
89     int64_t size,
90     ExceptionState& exception_state) {
91   ExecutionContext* secure_context = worker.GetExecutionContext();
92   if (!secure_context->GetSecurityOrigin()->CanAccessFileSystem()) {
93     exception_state.ThrowSecurityError(file_error::kSecurityErrorMessage);
94     return nullptr;
95   } else if (secure_context->GetSecurityOrigin()->IsLocal()) {
96     UseCounter::Count(secure_context, WebFeature::kFileAccessedFileSystem);
97   }
98 
99   mojom::blink::FileSystemType file_system_type =
100       static_cast<mojom::blink::FileSystemType>(type);
101   if (!DOMFileSystemBase::IsValidType(file_system_type)) {
102     exception_state.ThrowDOMException(
103         DOMExceptionCode::kInvalidModificationError,
104         "the type must be kTemporary or kPersistent.");
105     return nullptr;
106   }
107 
108   auto* sync_helper = MakeGarbageCollected<FileSystemCallbacksSyncHelper>();
109 
110   auto success_callback_wrapper =
111       WTF::Bind(&FileSystemCallbacksSyncHelper::OnSuccess,
112                 WrapPersistentIfNeeded(sync_helper));
113   auto error_callback_wrapper =
114       WTF::Bind(&FileSystemCallbacksSyncHelper::OnError,
115                 WrapPersistentIfNeeded(sync_helper));
116 
117   auto callbacks = std::make_unique<FileSystemCallbacks>(
118       std::move(success_callback_wrapper), std::move(error_callback_wrapper),
119       &worker, file_system_type);
120 
121   LocalFileSystem::From(worker)->RequestFileSystem(
122       file_system_type, size, std::move(callbacks),
123       LocalFileSystem::kSynchronous);
124   DOMFileSystem* file_system = sync_helper->GetResultOrThrow(exception_state);
125   return file_system ? MakeGarbageCollected<DOMFileSystemSync>(file_system)
126                      : nullptr;
127 }
128 
webkitResolveLocalFileSystemURL(WorkerGlobalScope & worker,const String & url,V8EntryCallback * success_callback,V8ErrorCallback * error_callback)129 void WorkerGlobalScopeFileSystem::webkitResolveLocalFileSystemURL(
130     WorkerGlobalScope& worker,
131     const String& url,
132     V8EntryCallback* success_callback,
133     V8ErrorCallback* error_callback) {
134   KURL completed_url = worker.CompleteURL(url);
135   ExecutionContext* secure_context = worker.GetExecutionContext();
136   auto error_callback_wrapper =
137       AsyncCallbackHelper::ErrorCallback(error_callback);
138 
139   if (!secure_context->GetSecurityOrigin()->CanAccessFileSystem() ||
140       !secure_context->GetSecurityOrigin()->CanRequest(completed_url)) {
141     DOMFileSystem::ReportError(&worker, std::move(error_callback_wrapper),
142                                base::File::FILE_ERROR_SECURITY);
143     return;
144   } else if (secure_context->GetSecurityOrigin()->IsLocal()) {
145     UseCounter::Count(secure_context, WebFeature::kFileAccessedFileSystem);
146   }
147 
148   if (!completed_url.IsValid()) {
149     DOMFileSystem::ReportError(&worker, std::move(error_callback_wrapper),
150                                base::File::FILE_ERROR_INVALID_URL);
151     return;
152   }
153 
154   auto success_callback_wrapper =
155       AsyncCallbackHelper::SuccessCallback<Entry>(success_callback);
156 
157   LocalFileSystem::From(worker)->ResolveURL(
158       completed_url,
159       std::make_unique<ResolveURICallbacks>(std::move(success_callback_wrapper),
160                                             std::move(error_callback_wrapper),
161                                             &worker),
162       LocalFileSystem::kAsynchronous);
163 }
164 
webkitResolveLocalFileSystemSyncURL(WorkerGlobalScope & worker,const String & url,ExceptionState & exception_state)165 EntrySync* WorkerGlobalScopeFileSystem::webkitResolveLocalFileSystemSyncURL(
166     WorkerGlobalScope& worker,
167     const String& url,
168     ExceptionState& exception_state) {
169   KURL completed_url = worker.CompleteURL(url);
170   ExecutionContext* secure_context = worker.GetExecutionContext();
171   if (!secure_context->GetSecurityOrigin()->CanAccessFileSystem() ||
172       !secure_context->GetSecurityOrigin()->CanRequest(completed_url)) {
173     exception_state.ThrowSecurityError(file_error::kSecurityErrorMessage);
174     return nullptr;
175   } else if (secure_context->GetSecurityOrigin()->IsLocal()) {
176     UseCounter::Count(secure_context, WebFeature::kFileAccessedFileSystem);
177   }
178 
179   if (!completed_url.IsValid()) {
180     exception_state.ThrowDOMException(DOMExceptionCode::kEncodingError,
181                                       "the URL '" + url + "' is invalid.");
182     return nullptr;
183   }
184 
185   auto* sync_helper = MakeGarbageCollected<EntryCallbacksSyncHelper>();
186 
187   auto success_callback_wrapper =
188       WTF::Bind(&EntryCallbacksSyncHelper::OnSuccess,
189                 WrapPersistentIfNeeded(sync_helper));
190   auto error_callback_wrapper = WTF::Bind(&EntryCallbacksSyncHelper::OnError,
191                                           WrapPersistentIfNeeded(sync_helper));
192 
193   std::unique_ptr<ResolveURICallbacks> callbacks =
194       std::make_unique<ResolveURICallbacks>(std::move(success_callback_wrapper),
195                                             std::move(error_callback_wrapper),
196                                             &worker);
197 
198   LocalFileSystem::From(worker)->ResolveURL(completed_url, std::move(callbacks),
199                                             LocalFileSystem::kSynchronous);
200 
201   Entry* entry = sync_helper->GetResultOrThrow(exception_state);
202   return entry ? EntrySync::Create(entry) : nullptr;
203 }
204 
205 static_assert(static_cast<int>(WorkerGlobalScopeFileSystem::kTemporary) ==
206                   static_cast<int>(mojom::blink::FileSystemType::kTemporary),
207               "WorkerGlobalScopeFileSystem::kTemporary should match "
208               "FileSystemTypeTemporary");
209 static_assert(static_cast<int>(WorkerGlobalScopeFileSystem::kPersistent) ==
210                   static_cast<int>(mojom::blink::FileSystemType::kPersistent),
211               "WorkerGlobalScopeFileSystem::kPersistent should match "
212               "FileSystemTypePersistent");
213 
214 }  // namespace blink
215