• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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 #include "ServiceWorker.h"
33 
34 #include "bindings/v8/ExceptionState.h"
35 #include "bindings/v8/ScriptPromiseResolverWithContext.h"
36 #include "bindings/v8/ScriptState.h"
37 #include "core/dom/MessagePort.h"
38 #include "modules/EventTargetModules.h"
39 #include "platform/NotImplemented.h"
40 #include "public/platform/WebMessagePortChannel.h"
41 #include "public/platform/WebServiceWorkerState.h"
42 #include "public/platform/WebString.h"
43 #include <v8.h>
44 
45 namespace WebCore {
46 
47 class ServiceWorker::ThenFunction FINAL : public ScriptFunction {
48 public:
create(PassRefPtr<ServiceWorker> observer)49     static PassOwnPtr<ScriptFunction> create(PassRefPtr<ServiceWorker> observer)
50     {
51         ExecutionContext* executionContext = observer->executionContext();
52         return adoptPtr(new ThenFunction(toIsolate(executionContext), observer));
53     }
54 private:
ThenFunction(v8::Isolate * isolate,PassRefPtr<ServiceWorker> observer)55     ThenFunction(v8::Isolate* isolate, PassRefPtr<ServiceWorker> observer)
56         : ScriptFunction(isolate)
57         , m_observer(observer)
58     {
59     }
60 
call(ScriptValue value)61     virtual ScriptValue call(ScriptValue value) OVERRIDE
62     {
63         m_observer->onPromiseResolved();
64         return value;
65     }
66 
67     RefPtr<ServiceWorker> m_observer;
68 };
69 
interfaceName() const70 const AtomicString& ServiceWorker::interfaceName() const
71 {
72     return EventTargetNames::ServiceWorker;
73 }
74 
postMessage(PassRefPtr<SerializedScriptValue> message,const MessagePortArray * ports,ExceptionState & exceptionState)75 void ServiceWorker::postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, ExceptionState& exceptionState)
76 {
77     // Disentangle the port in preparation for sending it to the remote context.
78     OwnPtr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(ports, exceptionState);
79     if (exceptionState.hadException())
80         return;
81 
82     blink::WebString messageString = message->toWireString();
83     OwnPtr<blink::WebMessagePortChannelArray> webChannels = MessagePort::toWebMessagePortChannelArray(channels.release());
84     m_outerWorker->postMessage(messageString, webChannels.leakPtr());
85 }
86 
isReady()87 bool ServiceWorker::isReady()
88 {
89     return m_proxyState == Ready;
90 }
91 
dispatchStateChangeEvent()92 void ServiceWorker::dispatchStateChangeEvent()
93 {
94     ASSERT(isReady());
95     this->dispatchEvent(Event::create(EventTypeNames::statechange));
96 }
97 
scope() const98 String ServiceWorker::scope() const
99 {
100     return m_outerWorker->scope().string();
101 }
102 
url() const103 String ServiceWorker::url() const
104 {
105     return m_outerWorker->url().string();
106 }
107 
state() const108 const AtomicString& ServiceWorker::state() const
109 {
110     DEFINE_STATIC_LOCAL(AtomicString, unknown, ("unknown", AtomicString::ConstructFromLiteral));
111     DEFINE_STATIC_LOCAL(AtomicString, parsed, ("parsed", AtomicString::ConstructFromLiteral));
112     DEFINE_STATIC_LOCAL(AtomicString, installing, ("installing", AtomicString::ConstructFromLiteral));
113     DEFINE_STATIC_LOCAL(AtomicString, installed, ("installed", AtomicString::ConstructFromLiteral));
114     DEFINE_STATIC_LOCAL(AtomicString, activating, ("activating", AtomicString::ConstructFromLiteral));
115     DEFINE_STATIC_LOCAL(AtomicString, active, ("active", AtomicString::ConstructFromLiteral));
116     DEFINE_STATIC_LOCAL(AtomicString, deactivated, ("deactivated", AtomicString::ConstructFromLiteral));
117 
118     switch (m_outerWorker->state()) {
119     case blink::WebServiceWorkerStateUnknown:
120         // The web platform should never see this internal state
121         ASSERT_NOT_REACHED();
122         return unknown;
123     case blink::WebServiceWorkerStateParsed:
124         return parsed;
125     case blink::WebServiceWorkerStateInstalling:
126         return installing;
127     case blink::WebServiceWorkerStateInstalled:
128         return installed;
129     case blink::WebServiceWorkerStateActivating:
130         return activating;
131     case blink::WebServiceWorkerStateActive:
132         return active;
133     case blink::WebServiceWorkerStateDeactivated:
134         return deactivated;
135     default:
136         ASSERT_NOT_REACHED();
137         return nullAtom;
138     }
139 }
140 
from(ExecutionContext * executionContext,WebType * worker)141 PassRefPtr<ServiceWorker> ServiceWorker::from(ExecutionContext* executionContext, WebType* worker)
142 {
143     if (!worker)
144         return PassRefPtr<ServiceWorker>();
145 
146     blink::WebServiceWorkerProxy* proxy = worker->proxy();
147     ServiceWorker* existingServiceWorker = proxy ? proxy->unwrap() : 0;
148     if (existingServiceWorker) {
149         ASSERT(existingServiceWorker->executionContext() == executionContext);
150         return existingServiceWorker;
151     }
152 
153     return create(executionContext, adoptPtr(worker));
154 }
155 
from(ScriptPromiseResolverWithContext * resolver,WebType * worker)156 PassRefPtr<ServiceWorker> ServiceWorker::from(ScriptPromiseResolverWithContext* resolver, WebType* worker)
157 {
158     RefPtr<ServiceWorker> serviceWorker = ServiceWorker::from(resolver->scriptState()->executionContext(), worker);
159     ScriptState::Scope scope(resolver->scriptState());
160     serviceWorker->waitOnPromise(resolver->promise());
161     return serviceWorker;
162 }
163 
setProxyState(ProxyState state)164 void ServiceWorker::setProxyState(ProxyState state)
165 {
166     if (m_proxyState == state)
167         return;
168     switch (m_proxyState) {
169     case Initial:
170         ASSERT(state == RegisterPromisePending || state == ContextStopped);
171         break;
172     case RegisterPromisePending:
173         ASSERT(state == Ready || state == ContextStopped);
174         break;
175     case Ready:
176         ASSERT(state == ContextStopped);
177         break;
178     case ContextStopped:
179         ASSERT_NOT_REACHED();
180         break;
181     }
182 
183     ProxyState oldState = m_proxyState;
184     m_proxyState = state;
185     if (oldState == Ready || state == Ready)
186         m_outerWorker->proxyReadyChanged();
187 }
188 
onPromiseResolved()189 void ServiceWorker::onPromiseResolved()
190 {
191     if (m_proxyState == ContextStopped)
192         return;
193     setProxyState(Ready);
194 }
195 
waitOnPromise(ScriptPromise promise)196 void ServiceWorker::waitOnPromise(ScriptPromise promise)
197 {
198     if (promise.isEmpty()) {
199         // The document was detached during registration. The state doesn't really
200         // matter since this ServiceWorker will immediately die.
201         setProxyState(ContextStopped);
202         return;
203     }
204     setProxyState(RegisterPromisePending);
205     promise.then(ThenFunction::create(this));
206 }
207 
hasPendingActivity() const208 bool ServiceWorker::hasPendingActivity() const
209 {
210     if (AbstractWorker::hasPendingActivity())
211         return true;
212     if (m_proxyState == ContextStopped)
213         return false;
214     return m_outerWorker->state() != blink::WebServiceWorkerStateDeactivated;
215 }
216 
stop()217 void ServiceWorker::stop()
218 {
219     setProxyState(ContextStopped);
220 }
221 
create(ExecutionContext * executionContext,PassOwnPtr<blink::WebServiceWorker> outerWorker)222 PassRefPtr<ServiceWorker> ServiceWorker::create(ExecutionContext* executionContext, PassOwnPtr<blink::WebServiceWorker> outerWorker)
223 {
224     RefPtr<ServiceWorker> worker = adoptRef(new ServiceWorker(executionContext, outerWorker));
225     worker->suspendIfNeeded();
226     return worker.release();
227 }
228 
ServiceWorker(ExecutionContext * executionContext,PassOwnPtr<blink::WebServiceWorker> worker)229 ServiceWorker::ServiceWorker(ExecutionContext* executionContext, PassOwnPtr<blink::WebServiceWorker> worker)
230     : AbstractWorker(executionContext)
231     , WebServiceWorkerProxy(this)
232     , m_outerWorker(worker)
233     , m_proxyState(Initial)
234 {
235     ScriptWrappable::init(this);
236     ASSERT(m_outerWorker);
237     m_outerWorker->setProxy(this);
238 }
239 
240 } // namespace WebCore
241