Add (entirely incorrect) fetching of ServiceWorker scripts.
[WebKit-https.git] / Source / WebCore / workers / service / server / SWServer.cpp
1 /*
2  * Copyright (C) 2017 Apple 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
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "SWServer.h"
28
29 #if ENABLE(SERVICE_WORKER)
30
31 #include "ExceptionCode.h"
32 #include "ExceptionData.h"
33 #include "Logging.h"
34 #include "SWServerRegistration.h"
35 #include "ServiceWorkerFetchResult.h"
36 #include "ServiceWorkerJobData.h"
37 #include <wtf/text/WTFString.h>
38
39 namespace WebCore {
40
41 SWServer::Connection::Connection(SWServer& server, uint64_t identifier)
42     : Identified(identifier)
43     , m_server(server)
44 {
45     m_server.registerConnection(*this);
46 }
47
48 SWServer::Connection::~Connection()
49 {
50     m_server.unregisterConnection(*this);
51 }
52
53 SWServer::~SWServer()
54 {
55     RELEASE_ASSERT(m_connections.isEmpty());
56     RELEASE_ASSERT(m_registrations.isEmpty());
57
58     ASSERT(m_taskQueue.isEmpty());
59     ASSERT(m_taskReplyQueue.isEmpty());
60
61     // For a SWServer to be cleanly shut down its thread must have finished and gone away.
62     // At this stage in development of the feature that actually never happens.
63     // But once it does start happening, this ASSERT will catch us doing it wrong.
64     Locker<Lock> locker(m_taskThreadLock);
65     ASSERT(!m_taskThread);
66 }
67
68 void SWServer::Connection::scheduleJobInServer(const ServiceWorkerJobData& jobData)
69 {
70     LOG(ServiceWorker, "Scheduling ServiceWorker job %" PRIu64 "-%" PRIu64 " in server", jobData.connectionIdentifier(), jobData.identifier());
71     ASSERT(identifier() == jobData.connectionIdentifier());
72
73     m_server.scheduleJob(jobData);
74 }
75
76 void SWServer::Connection::finishFetchingScriptInServer(const ServiceWorkerFetchResult& result)
77 {
78     m_server.scriptFetchFinished(result);
79 }
80
81 SWServer::SWServer()
82 {
83     m_taskThread = Thread::create(ASCIILiteral("ServiceWorker Task Thread"), [this] {
84         taskThreadEntryPoint();
85     });
86 }
87
88 void SWServer::scheduleJob(const ServiceWorkerJobData& jobData)
89 {
90     ASSERT(m_connections.contains(jobData.connectionIdentifier()));
91
92     auto result = m_registrations.add(jobData.registrationKey(), nullptr);
93     if (result.isNewEntry)
94         result.iterator->value = std::make_unique<SWServerRegistration>(*this, jobData.registrationKey());
95
96     ASSERT(result.iterator->value);
97
98     result.iterator->value->enqueueJob(jobData);
99 }
100
101 void SWServer::rejectJob(const ServiceWorkerJobData& jobData, const ExceptionData& exceptionData)
102 {
103     LOG(ServiceWorker, "Rejected ServiceWorker job %" PRIu64 "-%" PRIu64 " in server", jobData.connectionIdentifier(), jobData.identifier());
104     auto* connection = m_connections.get(jobData.connectionIdentifier());
105     if (!connection)
106         return;
107
108     connection->rejectJobInClient(jobData.identifier(), exceptionData);
109 }
110
111 void SWServer::resolveJob(const ServiceWorkerJobData& jobData, const ServiceWorkerRegistrationData& registrationData)
112 {
113     LOG(ServiceWorker, "Resolved ServiceWorker job %" PRIu64 "-%" PRIu64 " in server with registration %" PRIu64, jobData.connectionIdentifier(), jobData.identifier(), registrationData.identifier);
114     auto* connection = m_connections.get(jobData.connectionIdentifier());
115     if (!connection)
116         return;
117
118     connection->resolveJobInClient(jobData.identifier(), registrationData);
119 }
120
121 void SWServer::startScriptFetch(const ServiceWorkerJobData& jobData)
122 {
123     LOG(ServiceWorker, "Server issuing startScriptFetch for current job %" PRIu64 "-%" PRIu64 " in client", jobData.connectionIdentifier(), jobData.identifier());
124     auto* connection = m_connections.get(jobData.connectionIdentifier());
125     if (!connection)
126         return;
127
128     connection->startScriptFetchInClient(jobData.identifier());
129 }
130
131 void SWServer::scriptFetchFinished(const ServiceWorkerFetchResult& result)
132 {
133     LOG(ServiceWorker, "Server handling scriptFetchFinished for current job %" PRIu64 "-%" PRIu64 " in client", result.connectionIdentifier, result.jobIdentifier);
134
135     ASSERT(m_connections.contains(result.connectionIdentifier));
136
137     auto registration = m_registrations.get(result.registrationKey);
138     if (!registration)
139         return;
140
141     registration->scriptFetchFinished(result);
142 }
143
144 void SWServer::taskThreadEntryPoint()
145 {
146     ASSERT(!isMainThread());
147
148     while (!m_taskQueue.isKilled())
149         m_taskQueue.waitForMessage().performTask();
150
151     Locker<Lock> locker(m_taskThreadLock);
152     m_taskThread = nullptr;
153 }
154
155 void SWServer::postTask(CrossThreadTask&& task)
156 {
157     m_taskQueue.append(WTFMove(task));
158 }
159
160 void SWServer::postTaskReply(CrossThreadTask&& task)
161 {
162     m_taskReplyQueue.append(WTFMove(task));
163
164     Locker<Lock> locker(m_mainThreadReplyLock);
165     if (m_mainThreadReplyScheduled)
166         return;
167
168     m_mainThreadReplyScheduled = true;
169     callOnMainThread([this] {
170         handleTaskRepliesOnMainThread();
171     });
172 }
173
174 void SWServer::handleTaskRepliesOnMainThread()
175 {
176     {
177         Locker<Lock> locker(m_mainThreadReplyLock);
178         m_mainThreadReplyScheduled = false;
179     }
180
181     while (auto task = m_taskReplyQueue.tryGetMessage())
182         task->performTask();
183 }
184
185 void SWServer::registerConnection(Connection& connection)
186 {
187     auto result = m_connections.add(connection.identifier(), nullptr);
188     ASSERT(result.isNewEntry);
189     result.iterator->value = &connection;
190 }
191
192 void SWServer::unregisterConnection(Connection& connection)
193 {
194     ASSERT(m_connections.get(connection.identifier()) == &connection);
195     m_connections.remove(connection.identifier());
196 }
197
198 } // namespace WebCore
199
200 #endif // ENABLE(SERVICE_WORKER)