1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/modules/background_sync/periodic_sync_manager.h"
6
7 #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
8 #include "third_party/blink/public/platform/platform.h"
9 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
10 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
11 #include "third_party/blink/renderer/bindings/modules/v8/v8_background_sync_options.h"
12 #include "third_party/blink/renderer/core/dom/dom_exception.h"
13 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
14 #include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h"
15 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
16
17 namespace blink {
18
PeriodicSyncManager(ServiceWorkerRegistration * registration,scoped_refptr<base::SequencedTaskRunner> task_runner)19 PeriodicSyncManager::PeriodicSyncManager(
20 ServiceWorkerRegistration* registration,
21 scoped_refptr<base::SequencedTaskRunner> task_runner)
22 : registration_(registration), task_runner_(std::move(task_runner)) {
23 DCHECK(registration_);
24 }
25
registerPeriodicSync(ScriptState * script_state,const String & tag,const BackgroundSyncOptions * options,ExceptionState & exception_state)26 ScriptPromise PeriodicSyncManager::registerPeriodicSync(
27 ScriptState* script_state,
28 const String& tag,
29 const BackgroundSyncOptions* options,
30 ExceptionState& exception_state) {
31 if (!registration_->active()) {
32 exception_state.ThrowDOMException(
33 DOMExceptionCode::kInvalidStateError,
34 "Registration failed - no active Service Worker");
35 return ScriptPromise();
36 }
37
38 auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
39 ScriptPromise promise = resolver->Promise();
40
41 mojom::blink::SyncRegistrationOptionsPtr sync_registration =
42 mojom::blink::SyncRegistrationOptions::New(tag, options->minInterval());
43
44 GetBackgroundSyncServiceRemote()->Register(
45 std::move(sync_registration), registration_->RegistrationId(),
46 WTF::Bind(&PeriodicSyncManager::RegisterCallback, WrapPersistent(this),
47 WrapPersistent(resolver)));
48
49 return promise;
50 }
51
getTags(ScriptState * script_state)52 ScriptPromise PeriodicSyncManager::getTags(ScriptState* script_state) {
53 auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
54 ScriptPromise promise = resolver->Promise();
55
56 // Creating a Periodic Background Sync registration requires an activated
57 // service worker, so if |registration_| has not been activated yet, we can
58 // skip the Mojo roundtrip.
59 if (!registration_->active()) {
60 return ScriptPromise::Cast(script_state,
61 v8::Array::New(script_state->GetIsolate()));
62 }
63
64 // TODO(crbug.com/932591): Optimize this to only get the tags from the browser
65 // process instead of the registrations themselves.
66 GetBackgroundSyncServiceRemote()->GetRegistrations(
67 registration_->RegistrationId(),
68 WTF::Bind(&PeriodicSyncManager::GetRegistrationsCallback,
69 WrapPersistent(this), WrapPersistent(resolver)));
70
71 return promise;
72 }
73
unregister(ScriptState * script_state,const String & tag)74 ScriptPromise PeriodicSyncManager::unregister(ScriptState* script_state,
75 const String& tag) {
76 auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
77 ScriptPromise promise = resolver->Promise();
78
79 // Silently succeed if there's no active service worker registration.
80 if (!registration_->active()) {
81 resolver->Resolve();
82 return promise;
83 }
84
85 GetBackgroundSyncServiceRemote()->Unregister(
86 registration_->RegistrationId(), tag,
87 WTF::Bind(&PeriodicSyncManager::UnregisterCallback, WrapPersistent(this),
88 WrapPersistent(resolver)));
89 return promise;
90 }
91
92 const mojo::Remote<mojom::blink::PeriodicBackgroundSyncService>&
GetBackgroundSyncServiceRemote()93 PeriodicSyncManager::GetBackgroundSyncServiceRemote() {
94 if (!background_sync_service_.is_bound()) {
95 Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
96 background_sync_service_.BindNewPipeAndPassReceiver());
97 }
98 return background_sync_service_;
99 }
100
RegisterCallback(ScriptPromiseResolver * resolver,mojom::blink::BackgroundSyncError error,mojom::blink::SyncRegistrationOptionsPtr options)101 void PeriodicSyncManager::RegisterCallback(
102 ScriptPromiseResolver* resolver,
103 mojom::blink::BackgroundSyncError error,
104 mojom::blink::SyncRegistrationOptionsPtr options) {
105 switch (error) {
106 case mojom::blink::BackgroundSyncError::NONE:
107 resolver->Resolve();
108 break;
109 case mojom::blink::BackgroundSyncError::NOT_FOUND:
110 NOTREACHED();
111 break;
112 case mojom::blink::BackgroundSyncError::STORAGE:
113 resolver->Reject(MakeGarbageCollected<DOMException>(
114 DOMExceptionCode::kUnknownError, "Unknown error."));
115 break;
116 case mojom::blink::BackgroundSyncError::NOT_ALLOWED:
117 resolver->Reject(MakeGarbageCollected<DOMException>(
118 DOMExceptionCode::kInvalidAccessError,
119 "Attempted to register a sync event without a "
120 "window or registration tag too long."));
121 break;
122 case mojom::blink::BackgroundSyncError::PERMISSION_DENIED:
123 resolver->Reject(MakeGarbageCollected<DOMException>(
124 DOMExceptionCode::kNotAllowedError, "Permission denied."));
125 break;
126 case mojom::blink::BackgroundSyncError::NO_SERVICE_WORKER:
127 resolver->Reject(MakeGarbageCollected<DOMException>(
128 DOMExceptionCode::kInvalidStateError,
129 "Registration failed - no active Service Worker"));
130 break;
131 }
132 }
133
GetRegistrationsCallback(ScriptPromiseResolver * resolver,mojom::blink::BackgroundSyncError error,WTF::Vector<mojom::blink::SyncRegistrationOptionsPtr> registrations)134 void PeriodicSyncManager::GetRegistrationsCallback(
135 ScriptPromiseResolver* resolver,
136 mojom::blink::BackgroundSyncError error,
137 WTF::Vector<mojom::blink::SyncRegistrationOptionsPtr> registrations) {
138 switch (error) {
139 case mojom::blink::BackgroundSyncError::NONE: {
140 Vector<String> tags;
141 for (const auto& registration : registrations)
142 tags.push_back(registration->tag);
143 resolver->Resolve(tags);
144 break;
145 }
146 case mojom::blink::BackgroundSyncError::NOT_FOUND:
147 case mojom::blink::BackgroundSyncError::NOT_ALLOWED:
148 case mojom::blink::BackgroundSyncError::PERMISSION_DENIED:
149 // These errors should never be returned from
150 // BackgroundSyncManager::GetPeriodicSyncRegistrations
151 NOTREACHED();
152 break;
153 case mojom::blink::BackgroundSyncError::STORAGE:
154 resolver->Reject(MakeGarbageCollected<DOMException>(
155 DOMExceptionCode::kUnknownError, "Unknown error."));
156 break;
157 case mojom::blink::BackgroundSyncError::NO_SERVICE_WORKER:
158 resolver->Reject(MakeGarbageCollected<DOMException>(
159 DOMExceptionCode::kUnknownError, "No service worker is active."));
160 break;
161 }
162 }
163
UnregisterCallback(ScriptPromiseResolver * resolver,mojom::blink::BackgroundSyncError error)164 void PeriodicSyncManager::UnregisterCallback(
165 ScriptPromiseResolver* resolver,
166 mojom::blink::BackgroundSyncError error) {
167 switch (error) {
168 case mojom::blink::BackgroundSyncError::NONE:
169 resolver->Resolve();
170 break;
171 case mojom::blink::BackgroundSyncError::NO_SERVICE_WORKER:
172 resolver->Reject(MakeGarbageCollected<DOMException>(
173 DOMExceptionCode::kUnknownError, "No service worker is active."));
174 break;
175 case mojom::blink::BackgroundSyncError::STORAGE:
176 resolver->Reject(MakeGarbageCollected<DOMException>(
177 DOMExceptionCode::kUnknownError, "Unknown error."));
178 break;
179 case mojom::blink::BackgroundSyncError::NOT_FOUND:
180 case mojom::blink::BackgroundSyncError::NOT_ALLOWED:
181 case mojom::BackgroundSyncError::PERMISSION_DENIED:
182 NOTREACHED();
183 break;
184 }
185 }
186
Trace(Visitor * visitor)187 void PeriodicSyncManager::Trace(Visitor* visitor) {
188 visitor->Trace(registration_);
189 ScriptWrappable::Trace(visitor);
190 }
191
192 } // namespace blink
193