Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / serviceworkers / ServiceWorkerGlobalScope.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 #include "config.h"
31 #include "ServiceWorkerGlobalScope.h"
32
33 #include "bindings/core/v8/ScriptPromise.h"
34 #include "bindings/core/v8/ScriptState.h"
35 #include "bindings/core/v8/V8ThrowException.h"
36 #include "core/events/Event.h"
37 #include "core/fetch/MemoryCache.h"
38 #include "core/fetch/ResourceLoaderOptions.h"
39 #include "core/inspector/ScriptCallStack.h"
40 #include "core/loader/ThreadableLoader.h"
41 #include "core/workers/WorkerClients.h"
42 #include "core/workers/WorkerThreadStartupData.h"
43 #include "modules/EventTargetModules.h"
44 #include "modules/serviceworkers/CacheStorage.h"
45 #include "modules/serviceworkers/FetchManager.h"
46 #include "modules/serviceworkers/Request.h"
47 #include "modules/serviceworkers/ServiceWorkerClients.h"
48 #include "modules/serviceworkers/ServiceWorkerGlobalScopeClient.h"
49 #include "modules/serviceworkers/ServiceWorkerThread.h"
50 #include "modules/serviceworkers/WaitUntilObserver.h"
51 #include "platform/network/ResourceRequest.h"
52 #include "platform/weborigin/KURL.h"
53 #include "public/platform/WebURL.h"
54 #include "wtf/CurrentTime.h"
55
56 namespace blink {
57
58 PassRefPtrWillBeRawPtr<ServiceWorkerGlobalScope> ServiceWorkerGlobalScope::create(ServiceWorkerThread* thread, PassOwnPtrWillBeRawPtr<WorkerThreadStartupData> startupData)
59 {
60     RefPtrWillBeRawPtr<ServiceWorkerGlobalScope> context = adoptRefWillBeNoop(new ServiceWorkerGlobalScope(startupData->m_scriptURL, startupData->m_userAgent, thread, monotonicallyIncreasingTime(), startupData->m_starterOrigin, startupData->m_workerClients.release()));
61
62     context->applyContentSecurityPolicyFromString(startupData->m_contentSecurityPolicy, startupData->m_contentSecurityPolicyType);
63
64     return context.release();
65 }
66
67 ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(const KURL& url, const String& userAgent, ServiceWorkerThread* thread, double timeOrigin, const SecurityOrigin* starterOrigin, PassOwnPtrWillBeRawPtr<WorkerClients> workerClients)
68     : WorkerGlobalScope(url, userAgent, thread, timeOrigin, starterOrigin, workerClients)
69     , m_fetchManager(adoptPtr(new FetchManager(this)))
70     , m_didEvaluateScript(false)
71     , m_hadErrorInTopLevelEventHandler(false)
72     , m_eventNestingLevel(0)
73 {
74 }
75
76 ServiceWorkerGlobalScope::~ServiceWorkerGlobalScope()
77 {
78 }
79
80 void ServiceWorkerGlobalScope::didEvaluateWorkerScript()
81 {
82     m_didEvaluateScript = true;
83 }
84
85 void ServiceWorkerGlobalScope::stopFetch()
86 {
87     m_fetchManager.clear();
88 }
89
90 String ServiceWorkerGlobalScope::scope(ExecutionContext* context)
91 {
92     return ServiceWorkerGlobalScopeClient::from(context)->scope().string();
93 }
94
95 CacheStorage* ServiceWorkerGlobalScope::caches(ExecutionContext* context)
96 {
97     if (!m_caches)
98         m_caches = CacheStorage::create(ServiceWorkerGlobalScopeClient::from(context)->cacheStorage());
99     return m_caches;
100 }
101
102 ScriptPromise ServiceWorkerGlobalScope::fetch(ScriptState* scriptState, Request* request)
103 {
104     if (!m_fetchManager)
105         return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "ServiceWorkerGlobalScope is shutting down."));
106     // "Let |r| be the associated request of the result of invoking the initial
107     // value of Request as constructor with |input| and |init| as arguments. If
108     // this throws an exception, reject |p| with it."
109     TrackExceptionState exceptionState;
110     Request* r = Request::create(this, request, exceptionState);
111     if (exceptionState.hadException()) {
112         // FIXME: We should throw the caught error.
113         return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), exceptionState.message()));
114     }
115     return m_fetchManager->fetch(scriptState, r->request());
116 }
117
118 ScriptPromise ServiceWorkerGlobalScope::fetch(ScriptState* scriptState, Request* request, const Dictionary& requestInit)
119 {
120     if (!m_fetchManager)
121         return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "ServiceWorkerGlobalScope is shutting down."));
122     // "Let |r| be the associated request of the result of invoking the initial
123     // value of Request as constructor with |input| and |init| as arguments. If
124     // this throws an exception, reject |p| with it."
125     TrackExceptionState exceptionState;
126     Request* r = Request::create(this, request, requestInit, exceptionState);
127     if (exceptionState.hadException()) {
128         // FIXME: We should throw the caught error.
129         return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), exceptionState.message()));
130     }
131     return m_fetchManager->fetch(scriptState, r->request());
132 }
133
134 ScriptPromise ServiceWorkerGlobalScope::fetch(ScriptState* scriptState, const String& urlstring)
135 {
136     if (!m_fetchManager)
137         return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "ServiceWorkerGlobalScope is shutting down."));
138     // "Let |r| be the associated request of the result of invoking the initial
139     // value of Request as constructor with |input| and |init| as arguments. If
140     // this throws an exception, reject |p| with it."
141     TrackExceptionState exceptionState;
142     Request* r = Request::create(this, urlstring, exceptionState);
143     if (exceptionState.hadException()) {
144         // FIXME: We should throw the caught error.
145         return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), exceptionState.message()));
146     }
147     return m_fetchManager->fetch(scriptState, r->request());
148 }
149
150 ScriptPromise ServiceWorkerGlobalScope::fetch(ScriptState* scriptState, const String& urlstring, const Dictionary& requestInit)
151 {
152     if (!m_fetchManager)
153         return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "ServiceWorkerGlobalScope is shutting down."));
154     // "Let |r| be the associated request of the result of invoking the initial
155     // value of Request as constructor with |input| and |init| as arguments. If
156     // this throws an exception, reject |p| with it."
157     TrackExceptionState exceptionState;
158     Request* r = Request::create(this, urlstring, requestInit, exceptionState);
159     if (exceptionState.hadException()) {
160         // FIXME: We should throw the caught error.
161         return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), exceptionState.message()));
162     }
163     return m_fetchManager->fetch(scriptState, r->request());
164 }
165
166 ServiceWorkerClients* ServiceWorkerGlobalScope::clients()
167 {
168     if (!m_clients)
169         m_clients = ServiceWorkerClients::create();
170     return m_clients;
171 }
172
173 void ServiceWorkerGlobalScope::close(ExceptionState& exceptionState)
174 {
175     exceptionState.throwDOMException(InvalidAccessError, "Not supported.");
176 }
177
178 bool ServiceWorkerGlobalScope::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
179 {
180     if (m_didEvaluateScript) {
181         if (eventType == EventTypeNames::install) {
182             RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(JSMessageSource, WarningMessageLevel, "Event handler of 'install' event must be added on the initial evaluation of worker script.");
183             addMessageToWorkerConsole(consoleMessage.release());
184         } else if (eventType == EventTypeNames::activate) {
185             RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(JSMessageSource, WarningMessageLevel, "Event handler of 'activate' event must be added on the initial evaluation of worker script.");
186             addMessageToWorkerConsole(consoleMessage.release());
187         }
188     }
189     return WorkerGlobalScope::addEventListener(eventType, listener, useCapture);
190 }
191
192 const AtomicString& ServiceWorkerGlobalScope::interfaceName() const
193 {
194     return EventTargetNames::ServiceWorkerGlobalScope;
195 }
196
197 bool ServiceWorkerGlobalScope::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
198 {
199     m_eventNestingLevel++;
200     bool result = WorkerGlobalScope::dispatchEvent(event.get());
201     if (event->interfaceName() == EventNames::ErrorEvent && m_eventNestingLevel == 2 && !event->defaultPrevented())
202         m_hadErrorInTopLevelEventHandler = true;
203     m_eventNestingLevel--;
204     return result;
205 }
206
207 void ServiceWorkerGlobalScope::dispatchExtendableEvent(PassRefPtrWillBeRawPtr<Event> event, WaitUntilObserver* observer)
208 {
209     ASSERT(m_eventNestingLevel == 0);
210     m_hadErrorInTopLevelEventHandler = false;
211
212     observer->willDispatchEvent();
213     dispatchEvent(event);
214     observer->didDispatchEvent(m_hadErrorInTopLevelEventHandler);
215 }
216
217 void ServiceWorkerGlobalScope::trace(Visitor* visitor)
218 {
219     visitor->trace(m_clients);
220     visitor->trace(m_caches);
221     WorkerGlobalScope::trace(visitor);
222 }
223
224 void ServiceWorkerGlobalScope::importScripts(const Vector<String>& urls, ExceptionState& exceptionState)
225 {
226     // Bust the MemoryCache to ensure script requests reach the browser-side
227     // and get added to and retrieved from the ServiceWorker's script cache.
228     // FIXME: Revisit in light of the solution to crbug/388375.
229     for (Vector<String>::const_iterator it = urls.begin(); it != urls.end(); ++it)
230         MemoryCache::removeURLFromCache(this->executionContext(), completeURL(*it));
231     WorkerGlobalScope::importScripts(urls, exceptionState);
232 }
233
234 void ServiceWorkerGlobalScope::logExceptionToConsole(const String& errorMessage, int scriptId, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtrWillBeRawPtr<ScriptCallStack> callStack)
235 {
236     WorkerGlobalScope::logExceptionToConsole(errorMessage, scriptId, sourceURL, lineNumber, columnNumber, callStack);
237     RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, errorMessage, sourceURL, lineNumber);
238     consoleMessage->setScriptId(scriptId);
239     consoleMessage->setCallStack(callStack);
240     addMessageToWorkerConsole(consoleMessage.release());
241 }
242
243 } // namespace blink