Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / serviceworkers / ServiceWorker.cpp
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/core/v8/ExceptionState.h"
35 #include "bindings/core/v8/ScriptPromiseResolver.h"
36 #include "bindings/core/v8/ScriptState.h"
37 #include "core/dom/MessagePort.h"
38 #include "core/events/Event.h"
39 #include "modules/EventTargetModules.h"
40 #include "platform/NotImplemented.h"
41 #include "public/platform/WebMessagePortChannel.h"
42 #include "public/platform/WebServiceWorkerState.h"
43 #include "public/platform/WebString.h"
44 #include <v8.h>
45
46 namespace blink {
47
48 class ServiceWorker::ThenFunction FINAL : public ScriptFunction {
49 public:
50     static v8::Handle<v8::Function> createFunction(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ServiceWorker> observer)
51     {
52         ThenFunction* self = new ThenFunction(scriptState, observer);
53         return self->bindToV8Function();
54     }
55
56     virtual void trace(Visitor* visitor) OVERRIDE
57     {
58         visitor->trace(m_observer);
59         ScriptFunction::trace(visitor);
60     }
61
62 private:
63     ThenFunction(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ServiceWorker> observer)
64         : ScriptFunction(scriptState)
65         , m_observer(observer)
66     {
67     }
68
69     virtual ScriptValue call(ScriptValue value) OVERRIDE
70     {
71         m_observer->onPromiseResolved();
72         return value;
73     }
74
75     RefPtrWillBeMember<ServiceWorker> m_observer;
76 };
77
78 const AtomicString& ServiceWorker::interfaceName() const
79 {
80     return EventTargetNames::ServiceWorker;
81 }
82
83 void ServiceWorker::postMessage(ExecutionContext*, PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, ExceptionState& exceptionState)
84 {
85     // Disentangle the port in preparation for sending it to the remote context.
86     OwnPtr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(ports, exceptionState);
87     if (exceptionState.hadException())
88         return;
89     if (m_outerWorker->state() == WebServiceWorkerStateRedundant) {
90         exceptionState.throwDOMException(InvalidStateError, "ServiceWorker is in redundant state.");
91         return;
92     }
93
94     WebString messageString = message->toWireString();
95     OwnPtr<WebMessagePortChannelArray> webChannels = MessagePort::toWebMessagePortChannelArray(channels.release());
96     m_outerWorker->postMessage(messageString, webChannels.leakPtr());
97 }
98
99 void ServiceWorker::terminate(ExceptionState& exceptionState)
100 {
101     exceptionState.throwDOMException(InvalidAccessError, "Not supported.");
102 }
103
104 bool ServiceWorker::isReady()
105 {
106     return m_proxyState == Ready;
107 }
108
109 void ServiceWorker::dispatchStateChangeEvent()
110 {
111     ASSERT(isReady());
112     this->dispatchEvent(Event::create(EventTypeNames::statechange));
113 }
114
115 String ServiceWorker::scriptURL() const
116 {
117     return m_outerWorker->url().string();
118 }
119
120 const AtomicString& ServiceWorker::state() const
121 {
122     DEFINE_STATIC_LOCAL(AtomicString, unknown, ("unknown", AtomicString::ConstructFromLiteral));
123     DEFINE_STATIC_LOCAL(AtomicString, parsed, ("parsed", AtomicString::ConstructFromLiteral));
124     DEFINE_STATIC_LOCAL(AtomicString, installing, ("installing", AtomicString::ConstructFromLiteral));
125     DEFINE_STATIC_LOCAL(AtomicString, installed, ("installed", AtomicString::ConstructFromLiteral));
126     DEFINE_STATIC_LOCAL(AtomicString, activating, ("activating", AtomicString::ConstructFromLiteral));
127     DEFINE_STATIC_LOCAL(AtomicString, activated, ("activated", AtomicString::ConstructFromLiteral));
128     DEFINE_STATIC_LOCAL(AtomicString, redundant, ("redundant", AtomicString::ConstructFromLiteral));
129
130     switch (m_outerWorker->state()) {
131     case WebServiceWorkerStateUnknown:
132         // The web platform should never see this internal state
133         ASSERT_NOT_REACHED();
134         return unknown;
135     case WebServiceWorkerStateParsed:
136         return parsed;
137     case WebServiceWorkerStateInstalling:
138         return installing;
139     case WebServiceWorkerStateInstalled:
140         return installed;
141     case WebServiceWorkerStateActivating:
142         return activating;
143     case WebServiceWorkerStateActivated:
144         return activated;
145     case WebServiceWorkerStateRedundant:
146         return redundant;
147     default:
148         ASSERT_NOT_REACHED();
149         return nullAtom;
150     }
151 }
152
153 PassRefPtrWillBeRawPtr<ServiceWorker> ServiceWorker::from(ExecutionContext* executionContext, WebType* worker)
154 {
155     if (!worker)
156         return nullptr;
157
158     RefPtrWillBeRawPtr<ServiceWorker> serviceWorker = getOrCreate(executionContext, worker);
159     if (serviceWorker->m_proxyState == Initial)
160         serviceWorker->setProxyState(Ready);
161     return serviceWorker.release();
162 }
163
164 PassRefPtrWillBeRawPtr<ServiceWorker> ServiceWorker::take(ScriptPromiseResolver* resolver, WebType* worker)
165 {
166     if (!worker)
167         return nullptr;
168
169     RefPtrWillBeRawPtr<ServiceWorker> serviceWorker = getOrCreate(resolver->scriptState()->executionContext(), worker);
170     ScriptState::Scope scope(resolver->scriptState());
171     if (serviceWorker->m_proxyState == Initial)
172         serviceWorker->waitOnPromise(resolver);
173     return serviceWorker;
174 }
175
176 void ServiceWorker::dispose(WebType* worker)
177 {
178     if (worker && !worker->proxy())
179         delete worker;
180 }
181
182 void ServiceWorker::setProxyState(ProxyState state)
183 {
184     if (m_proxyState == state)
185         return;
186     switch (m_proxyState) {
187     case Initial:
188         ASSERT(state == RegisterPromisePending || state == Ready || state == ContextStopped);
189         break;
190     case RegisterPromisePending:
191         ASSERT(state == Ready || state == ContextStopped);
192         break;
193     case Ready:
194         ASSERT(state == ContextStopped);
195         break;
196     case ContextStopped:
197         ASSERT_NOT_REACHED();
198         break;
199     }
200
201     ProxyState oldState = m_proxyState;
202     m_proxyState = state;
203     if (oldState == Ready || state == Ready)
204         m_outerWorker->proxyReadyChanged();
205 }
206
207 void ServiceWorker::onPromiseResolved()
208 {
209     if (m_proxyState == ContextStopped)
210         return;
211     setProxyState(Ready);
212 }
213
214 void ServiceWorker::waitOnPromise(ScriptPromiseResolver* resolver)
215 {
216     if (resolver->promise().isEmpty()) {
217         // The document was detached during registration. The state doesn't really
218         // matter since this ServiceWorker will immediately die.
219         setProxyState(ContextStopped);
220         return;
221     }
222     setProxyState(RegisterPromisePending);
223     resolver->promise().then(ThenFunction::createFunction(resolver->scriptState(), this));
224 }
225
226 bool ServiceWorker::hasPendingActivity() const
227 {
228     if (AbstractWorker::hasPendingActivity())
229         return true;
230     if (m_proxyState == ContextStopped)
231         return false;
232     return m_outerWorker->state() != WebServiceWorkerStateRedundant;
233 }
234
235 void ServiceWorker::stop()
236 {
237     setProxyState(ContextStopped);
238 }
239
240 PassRefPtrWillBeRawPtr<ServiceWorker> ServiceWorker::getOrCreate(ExecutionContext* executionContext, WebType* outerWorker)
241 {
242     if (!outerWorker)
243         return nullptr;
244
245     WebServiceWorkerProxy* proxy = outerWorker->proxy();
246     ServiceWorker* existingServiceWorker = proxy ? proxy->unwrap() : 0;
247     if (existingServiceWorker) {
248         ASSERT(existingServiceWorker->executionContext() == executionContext);
249         return existingServiceWorker;
250     }
251
252     RefPtrWillBeRawPtr<ServiceWorker> worker = adoptRefWillBeNoop(new ServiceWorker(executionContext, adoptPtr(outerWorker)));
253     worker->suspendIfNeeded();
254     return worker.release();
255 }
256
257 ServiceWorker::ServiceWorker(ExecutionContext* executionContext, PassOwnPtr<WebServiceWorker> worker)
258     : AbstractWorker(executionContext)
259     , WebServiceWorkerProxy(this)
260     , m_outerWorker(worker)
261     , m_proxyState(Initial)
262 {
263     ASSERT(m_outerWorker);
264     m_outerWorker->setProxy(this);
265 }
266
267 } // namespace blink