1 // Copyright 2015 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/sync_manager.h"
6 
7 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
8 #include "third_party/blink/public/platform/platform.h"
9 #include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h"
10 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
11 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.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 #include "third_party/blink/renderer/platform/bindings/script_state.h"
17 #include "third_party/blink/renderer/platform/heap/heap.h"
18 #include "third_party/blink/renderer/platform/heap/persistent.h"
19 #include "third_party/blink/renderer/platform/wtf/functional.h"
20 
21 namespace blink {
22 
SyncManager(ServiceWorkerRegistration * registration,scoped_refptr<base::SequencedTaskRunner> task_runner)23 SyncManager::SyncManager(ServiceWorkerRegistration* registration,
24                          scoped_refptr<base::SequencedTaskRunner> task_runner)
25     : registration_(registration),
26       background_sync_service_(registration->GetExecutionContext()) {
27   DCHECK(registration);
28   registration->GetExecutionContext()->GetBrowserInterfaceBroker().GetInterface(
29       background_sync_service_.BindNewPipeAndPassReceiver(task_runner));
30 }
31 
registerFunction(ScriptState * script_state,const String & tag,ExceptionState & exception_state)32 ScriptPromise SyncManager::registerFunction(ScriptState* script_state,
33                                             const String& tag,
34                                             ExceptionState& exception_state) {
35   if (!registration_->active()) {
36     exception_state.ThrowDOMException(
37         DOMExceptionCode::kInvalidStateError,
38         "Registration failed - no active Service Worker");
39     return ScriptPromise();
40   }
41 
42   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
43   ScriptPromise promise = resolver->Promise();
44 
45   mojom::blink::SyncRegistrationOptionsPtr sync_registration =
46       mojom::blink::SyncRegistrationOptions::New();
47   sync_registration->tag = tag;
48 
49   background_sync_service_->Register(
50       std::move(sync_registration), registration_->RegistrationId(),
51       WTF::Bind(&SyncManager::RegisterCallback, WrapPersistent(this),
52                 WrapPersistent(resolver)));
53 
54   return promise;
55 }
56 
getTags(ScriptState * script_state)57 ScriptPromise SyncManager::getTags(ScriptState* script_state) {
58   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
59   ScriptPromise promise = resolver->Promise();
60 
61   background_sync_service_->GetRegistrations(
62       registration_->RegistrationId(),
63       WTF::Bind(&SyncManager::GetRegistrationsCallback,
64                 WrapPersistent(resolver)));
65 
66   return promise;
67 }
68 
RegisterCallback(ScriptPromiseResolver * resolver,mojom::blink::BackgroundSyncError error,mojom::blink::SyncRegistrationOptionsPtr options)69 void SyncManager::RegisterCallback(
70     ScriptPromiseResolver* resolver,
71     mojom::blink::BackgroundSyncError error,
72     mojom::blink::SyncRegistrationOptionsPtr options) {
73   // TODO(iclelland): Determine the correct error message to return in each case
74   switch (error) {
75     case mojom::blink::BackgroundSyncError::NONE:
76       if (!options) {
77         resolver->Resolve(v8::Null(resolver->GetScriptState()->GetIsolate()));
78         return;
79       }
80       resolver->Resolve();
81       // Let the service know that the registration promise is resolved so that
82       // it can fire the event.
83 
84       background_sync_service_->DidResolveRegistration(
85           mojom::blink::BackgroundSyncRegistrationInfo::New(
86               registration_->RegistrationId(), options->tag,
87               mojom::blink::BackgroundSyncType::ONE_SHOT));
88       break;
89     case mojom::blink::BackgroundSyncError::NOT_FOUND:
90       NOTREACHED();
91       break;
92     case mojom::blink::BackgroundSyncError::STORAGE:
93       resolver->Reject(MakeGarbageCollected<DOMException>(
94           DOMExceptionCode::kUnknownError, "Background Sync is disabled."));
95       break;
96     case mojom::blink::BackgroundSyncError::NOT_ALLOWED:
97       resolver->Reject(MakeGarbageCollected<DOMException>(
98           DOMExceptionCode::kInvalidAccessError,
99           "Attempted to register a sync event without a "
100           "window or registration tag too long."));
101       break;
102     case mojom::blink::BackgroundSyncError::PERMISSION_DENIED:
103       resolver->Reject(MakeGarbageCollected<DOMException>(
104           DOMExceptionCode::kNotAllowedError, "Permission denied."));
105       break;
106     case mojom::blink::BackgroundSyncError::NO_SERVICE_WORKER:
107       resolver->Reject(MakeGarbageCollected<DOMException>(
108           DOMExceptionCode::kInvalidStateError,
109           "Registration failed - no active Service Worker"));
110       break;
111   }
112 }
113 
114 // static
GetRegistrationsCallback(ScriptPromiseResolver * resolver,mojom::blink::BackgroundSyncError error,WTF::Vector<mojom::blink::SyncRegistrationOptionsPtr> registrations)115 void SyncManager::GetRegistrationsCallback(
116     ScriptPromiseResolver* resolver,
117     mojom::blink::BackgroundSyncError error,
118     WTF::Vector<mojom::blink::SyncRegistrationOptionsPtr> registrations) {
119   // TODO(iclelland): Determine the correct error message to return in each case
120   switch (error) {
121     case mojom::blink::BackgroundSyncError::NONE: {
122       Vector<String> tags;
123       for (const auto& r : registrations) {
124         tags.push_back(r->tag);
125       }
126       resolver->Resolve(tags);
127       break;
128     }
129     case mojom::blink::BackgroundSyncError::NOT_FOUND:
130     case mojom::blink::BackgroundSyncError::NOT_ALLOWED:
131     case mojom::blink::BackgroundSyncError::PERMISSION_DENIED:
132       // These errors should never be returned from
133       // BackgroundSyncManager::GetRegistrations
134       NOTREACHED();
135       break;
136     case mojom::blink::BackgroundSyncError::STORAGE:
137       resolver->Reject(MakeGarbageCollected<DOMException>(
138           DOMExceptionCode::kUnknownError, "Background Sync is disabled."));
139       break;
140     case mojom::blink::BackgroundSyncError::NO_SERVICE_WORKER:
141       resolver->Reject(MakeGarbageCollected<DOMException>(
142           DOMExceptionCode::kUnknownError, "No service worker is active."));
143       break;
144   }
145 }
146 
Trace(Visitor * visitor) const147 void SyncManager::Trace(Visitor* visitor) const {
148   visitor->Trace(registration_);
149   visitor->Trace(background_sync_service_);
150   ScriptWrappable::Trace(visitor);
151 }
152 
153 }  // namespace blink
154