| 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 "WebSWServerConnection.h" |
| 28 | |
| 29 | #if ENABLE(SERVICE_WORKER) |
| 30 | |
| 31 | #include "DataReference.h" |
| 32 | #include "FormDataReference.h" |
| 33 | #include "Logging.h" |
| 34 | #include "NetworkConnectionToWebProcessMessages.h" |
| 35 | #include "NetworkProcess.h" |
| 36 | #include "ServiceWorkerClientFetchMessages.h" |
| 37 | #include "WebCoreArgumentCoders.h" |
| 38 | #include "WebProcess.h" |
| 39 | #include "WebProcessMessages.h" |
| 40 | #include "WebSWClientConnectionMessages.h" |
| 41 | #include "WebSWContextManagerConnectionMessages.h" |
| 42 | #include "WebSWServerConnectionMessages.h" |
| 43 | #include "WebSWServerToContextConnection.h" |
| 44 | #include <WebCore/DocumentIdentifier.h> |
| 45 | #include <WebCore/ExceptionData.h> |
| 46 | #include <WebCore/NotImplemented.h> |
| 47 | #include <WebCore/SWServerRegistration.h> |
| 48 | #include <WebCore/SecurityOrigin.h> |
| 49 | #include <WebCore/ServiceWorkerClientData.h> |
| 50 | #include <WebCore/ServiceWorkerClientIdentifier.h> |
| 51 | #include <WebCore/ServiceWorkerContextData.h> |
| 52 | #include <WebCore/ServiceWorkerJobData.h> |
| 53 | #include <WebCore/ServiceWorkerUpdateViaCache.h> |
| 54 | #include <wtf/Algorithms.h> |
| 55 | #include <wtf/MainThread.h> |
| 56 | |
| 57 | namespace WebKit { |
| 58 | using namespace PAL; |
| 59 | using namespace WebCore; |
| 60 | |
| 61 | #define SWSERVERCONNECTION_RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(m_sessionID.isAlwaysOnLoggingAllowed(), ServiceWorker, "%p - WebSWServerConnection::" fmt, this, ##__VA_ARGS__) |
| 62 | #define SWSERVERCONNECTION_RELEASE_LOG_ERROR_IF_ALLOWED(fmt, ...) RELEASE_LOG_ERROR_IF(m_sessionID.isAlwaysOnLoggingAllowed(), ServiceWorker, "%p - WebSWServerConnection::" fmt, this, ##__VA_ARGS__) |
| 63 | |
| 64 | WebSWServerConnection::WebSWServerConnection(NetworkProcess& networkProcess, SWServer& server, IPC::Connection& connection, SessionID sessionID) |
| 65 | : SWServer::Connection(server) |
| 66 | , m_sessionID(sessionID) |
| 67 | , m_contentConnection(connection) |
| 68 | , m_networkProcess(networkProcess) |
| 69 | { |
| 70 | networkProcess.registerSWServerConnection(*this); |
| 71 | } |
| 72 | |
| 73 | WebSWServerConnection::~WebSWServerConnection() |
| 74 | { |
| 75 | m_networkProcess->unregisterSWServerConnection(*this); |
| 76 | for (const auto& keyValue : m_clientOrigins) |
| 77 | server().unregisterServiceWorkerClient(keyValue.value, keyValue.key); |
| 78 | } |
| 79 | |
| 80 | void WebSWServerConnection::rejectJobInClient(ServiceWorkerJobIdentifier jobIdentifier, const ExceptionData& exceptionData) |
| 81 | { |
| 82 | send(Messages::WebSWClientConnection::JobRejectedInServer(jobIdentifier, exceptionData)); |
| 83 | } |
| 84 | |
| 85 | void WebSWServerConnection::resolveRegistrationJobInClient(ServiceWorkerJobIdentifier jobIdentifier, const ServiceWorkerRegistrationData& registrationData, ShouldNotifyWhenResolved shouldNotifyWhenResolved) |
| 86 | { |
| 87 | send(Messages::WebSWClientConnection::RegistrationJobResolvedInServer(jobIdentifier, registrationData, shouldNotifyWhenResolved)); |
| 88 | } |
| 89 | |
| 90 | void WebSWServerConnection::resolveUnregistrationJobInClient(ServiceWorkerJobIdentifier jobIdentifier, const ServiceWorkerRegistrationKey& registrationKey, bool unregistrationResult) |
| 91 | { |
| 92 | send(Messages::WebSWClientConnection::UnregistrationJobResolvedInServer(jobIdentifier, unregistrationResult)); |
| 93 | } |
| 94 | |
| 95 | void WebSWServerConnection::startScriptFetchInClient(ServiceWorkerJobIdentifier jobIdentifier, const ServiceWorkerRegistrationKey& registrationKey, FetchOptions::Cache cachePolicy) |
| 96 | { |
| 97 | send(Messages::WebSWClientConnection::StartScriptFetchForServer(jobIdentifier, registrationKey, cachePolicy)); |
| 98 | } |
| 99 | |
| 100 | void WebSWServerConnection::updateRegistrationStateInClient(ServiceWorkerRegistrationIdentifier identifier, ServiceWorkerRegistrationState state, const Optional<ServiceWorkerData>& serviceWorkerData) |
| 101 | { |
| 102 | send(Messages::WebSWClientConnection::UpdateRegistrationState(identifier, state, serviceWorkerData)); |
| 103 | } |
| 104 | |
| 105 | void WebSWServerConnection::fireUpdateFoundEvent(ServiceWorkerRegistrationIdentifier identifier) |
| 106 | { |
| 107 | send(Messages::WebSWClientConnection::FireUpdateFoundEvent(identifier)); |
| 108 | } |
| 109 | |
| 110 | void WebSWServerConnection::setRegistrationLastUpdateTime(ServiceWorkerRegistrationIdentifier identifier, WallTime lastUpdateTime) |
| 111 | { |
| 112 | send(Messages::WebSWClientConnection::SetRegistrationLastUpdateTime(identifier, lastUpdateTime)); |
| 113 | } |
| 114 | |
| 115 | void WebSWServerConnection::setRegistrationUpdateViaCache(ServiceWorkerRegistrationIdentifier identifier, ServiceWorkerUpdateViaCache updateViaCache) |
| 116 | { |
| 117 | send(Messages::WebSWClientConnection::SetRegistrationUpdateViaCache(identifier, updateViaCache)); |
| 118 | } |
| 119 | |
| 120 | void WebSWServerConnection::notifyClientsOfControllerChange(const HashSet<DocumentIdentifier>& contextIdentifiers, const ServiceWorkerData& newController) |
| 121 | { |
| 122 | send(Messages::WebSWClientConnection::NotifyClientsOfControllerChange(contextIdentifiers, newController)); |
| 123 | } |
| 124 | |
| 125 | void WebSWServerConnection::updateWorkerStateInClient(ServiceWorkerIdentifier worker, ServiceWorkerState state) |
| 126 | { |
| 127 | send(Messages::WebSWClientConnection::UpdateWorkerState(worker, state)); |
| 128 | } |
| 129 | |
| 130 | void WebSWServerConnection::cancelFetch(ServiceWorkerRegistrationIdentifier serviceWorkerRegistrationIdentifier, FetchIdentifier fetchIdentifier) |
| 131 | { |
| 132 | SWSERVERCONNECTION_RELEASE_LOG_IF_ALLOWED("cancelFetch: %s" , fetchIdentifier.loggingString().utf8().data()); |
| 133 | auto* worker = server().activeWorkerFromRegistrationID(serviceWorkerRegistrationIdentifier); |
| 134 | if (!worker || !worker->isRunning()) |
| 135 | return; |
| 136 | |
| 137 | auto serviceWorkerIdentifier = worker->identifier(); |
| 138 | server().runServiceWorkerIfNecessary(serviceWorkerIdentifier, [weakThis = makeWeakPtr(this), this, serviceWorkerIdentifier, fetchIdentifier](auto* contextConnection) mutable { |
| 139 | if (weakThis && contextConnection) |
| 140 | static_cast<WebSWServerToContextConnection&>(*contextConnection).cancelFetch(this->identifier(), fetchIdentifier, serviceWorkerIdentifier); |
| 141 | }); |
| 142 | } |
| 143 | |
| 144 | void WebSWServerConnection::continueDidReceiveFetchResponse(ServiceWorkerRegistrationIdentifier serviceWorkerRegistrationIdentifier, FetchIdentifier fetchIdentifier) |
| 145 | { |
| 146 | auto* worker = server().activeWorkerFromRegistrationID(serviceWorkerRegistrationIdentifier); |
| 147 | if (!worker || !worker->isRunning()) |
| 148 | return; |
| 149 | |
| 150 | auto serviceWorkerIdentifier = worker->identifier(); |
| 151 | server().runServiceWorkerIfNecessary(serviceWorkerIdentifier, [weakThis = makeWeakPtr(this), this, serviceWorkerIdentifier, fetchIdentifier](auto* contextConnection) mutable { |
| 152 | if (weakThis && contextConnection) |
| 153 | static_cast<WebSWServerToContextConnection&>(*contextConnection).continueDidReceiveFetchResponse(this->identifier(), fetchIdentifier, serviceWorkerIdentifier); |
| 154 | }); |
| 155 | } |
| 156 | |
| 157 | void WebSWServerConnection::startFetch(ServiceWorkerRegistrationIdentifier serviceWorkerRegistrationIdentifier, FetchIdentifier fetchIdentifier, ResourceRequest&& request, FetchOptions&& options, IPC::FormDataReference&& formData, String&& referrer) |
| 158 | { |
| 159 | auto* worker = server().activeWorkerFromRegistrationID(serviceWorkerRegistrationIdentifier); |
| 160 | if (!worker) { |
| 161 | SWSERVERCONNECTION_RELEASE_LOG_ERROR_IF_ALLOWED("startFetch: fetchIdentifier: %s -> DidNotHandle because no active worker" , fetchIdentifier.loggingString().utf8().data()); |
| 162 | m_contentConnection->send(Messages::ServiceWorkerClientFetch::DidNotHandle { }, fetchIdentifier.toUInt64()); |
| 163 | return; |
| 164 | } |
| 165 | auto serviceWorkerIdentifier = worker->identifier(); |
| 166 | |
| 167 | auto runServerWorkerAndStartFetch = [weakThis = makeWeakPtr(this), this, fetchIdentifier, serviceWorkerIdentifier, request = WTFMove(request), options = WTFMove(options), formData = WTFMove(formData), referrer = WTFMove(referrer)](bool success) mutable { |
| 168 | if (!weakThis) |
| 169 | return; |
| 170 | |
| 171 | if (!success) { |
| 172 | SWSERVERCONNECTION_RELEASE_LOG_ERROR_IF_ALLOWED("startFetch: fetchIdentifier: %s DidNotHandle because worker did not become activated" , fetchIdentifier.loggingString().utf8().data()); |
| 173 | m_contentConnection->send(Messages::ServiceWorkerClientFetch::DidNotHandle { }, fetchIdentifier.toUInt64()); |
| 174 | return; |
| 175 | } |
| 176 | |
| 177 | auto* worker = server().workerByID(serviceWorkerIdentifier); |
| 178 | if (!worker) { |
| 179 | m_contentConnection->send(Messages::ServiceWorkerClientFetch::DidNotHandle { }, fetchIdentifier.toUInt64()); |
| 180 | return; |
| 181 | } |
| 182 | |
| 183 | if (!worker->contextConnection()) |
| 184 | m_networkProcess->createServerToContextConnection(worker->registrableDomain(), server().sessionID()); |
| 185 | |
| 186 | server().runServiceWorkerIfNecessary(serviceWorkerIdentifier, [weakThis = WTFMove(weakThis), this, fetchIdentifier, serviceWorkerIdentifier, request = WTFMove(request), options = WTFMove(options), formData = WTFMove(formData), referrer = WTFMove(referrer)](auto* contextConnection) { |
| 187 | if (!weakThis) |
| 188 | return; |
| 189 | |
| 190 | if (contextConnection) { |
| 191 | SWSERVERCONNECTION_RELEASE_LOG_IF_ALLOWED("startFetch: Starting fetch %s via service worker %s" , fetchIdentifier.loggingString().utf8().data(), serviceWorkerIdentifier.loggingString().utf8().data()); |
| 192 | static_cast<WebSWServerToContextConnection&>(*contextConnection).startFetch(m_sessionID, m_contentConnection.get(), this->identifier(), fetchIdentifier, serviceWorkerIdentifier, request, options, formData, referrer); |
| 193 | } else { |
| 194 | SWSERVERCONNECTION_RELEASE_LOG_ERROR_IF_ALLOWED("startFetch: fetchIdentifier: %s DidNotHandle because failed to run service worker" , fetchIdentifier.loggingString().utf8().data()); |
| 195 | m_contentConnection->send(Messages::ServiceWorkerClientFetch::DidNotHandle { }, fetchIdentifier.toUInt64()); |
| 196 | } |
| 197 | }); |
| 198 | }; |
| 199 | |
| 200 | if (worker->state() == ServiceWorkerState::Activating) { |
| 201 | worker->whenActivated(WTFMove(runServerWorkerAndStartFetch)); |
| 202 | return; |
| 203 | } |
| 204 | ASSERT(worker->state() == ServiceWorkerState::Activated); |
| 205 | runServerWorkerAndStartFetch(true); |
| 206 | } |
| 207 | |
| 208 | void WebSWServerConnection::postMessageToServiceWorker(ServiceWorkerIdentifier destinationIdentifier, MessageWithMessagePorts&& message, const ServiceWorkerOrClientIdentifier& sourceIdentifier) |
| 209 | { |
| 210 | auto* destinationWorker = server().workerByID(destinationIdentifier); |
| 211 | if (!destinationWorker) |
| 212 | return; |
| 213 | |
| 214 | Optional<ServiceWorkerOrClientData> sourceData; |
| 215 | WTF::switchOn(sourceIdentifier, [&](ServiceWorkerIdentifier identifier) { |
| 216 | if (auto* sourceWorker = server().workerByID(identifier)) |
| 217 | sourceData = ServiceWorkerOrClientData { sourceWorker->data() }; |
| 218 | }, [&](ServiceWorkerClientIdentifier identifier) { |
| 219 | if (auto clientData = destinationWorker->findClientByIdentifier(identifier)) |
| 220 | sourceData = ServiceWorkerOrClientData { *clientData }; |
| 221 | }); |
| 222 | |
| 223 | if (!sourceData) |
| 224 | return; |
| 225 | |
| 226 | if (!destinationWorker->contextConnection()) |
| 227 | m_networkProcess->createServerToContextConnection(destinationWorker->registrableDomain(), server().sessionID()); |
| 228 | |
| 229 | // It's possible this specific worker cannot be re-run (e.g. its registration has been removed) |
| 230 | server().runServiceWorkerIfNecessary(destinationIdentifier, [destinationIdentifier, message = WTFMove(message), sourceData = WTFMove(*sourceData)](auto* contextConnection) mutable { |
| 231 | if (contextConnection) |
| 232 | sendToContextProcess(*contextConnection, Messages::WebSWContextManagerConnection::PostMessageToServiceWorker { destinationIdentifier, WTFMove(message), WTFMove(sourceData) }); |
| 233 | }); |
| 234 | } |
| 235 | |
| 236 | void WebSWServerConnection::scheduleJobInServer(ServiceWorkerJobData&& jobData) |
| 237 | { |
| 238 | RegistrableDomain registrableDomain(jobData.scriptURL); |
| 239 | if (!m_networkProcess->serverToContextConnectionForRegistrableDomain(registrableDomain)) |
| 240 | m_networkProcess->createServerToContextConnection(registrableDomain, server().sessionID()); |
| 241 | |
| 242 | SWSERVERCONNECTION_RELEASE_LOG_IF_ALLOWED("Scheduling ServiceWorker job %s in server" , jobData.identifier().loggingString().utf8().data()); |
| 243 | ASSERT(identifier() == jobData.connectionIdentifier()); |
| 244 | |
| 245 | server().scheduleJob(WTFMove(jobData)); |
| 246 | } |
| 247 | |
| 248 | void WebSWServerConnection::postMessageToServiceWorkerClient(DocumentIdentifier destinationContextIdentifier, MessageWithMessagePorts&& message, ServiceWorkerIdentifier sourceIdentifier, const String& sourceOrigin) |
| 249 | { |
| 250 | auto* sourceServiceWorker = server().workerByID(sourceIdentifier); |
| 251 | if (!sourceServiceWorker) |
| 252 | return; |
| 253 | |
| 254 | send(Messages::WebSWClientConnection::PostMessageToServiceWorkerClient { destinationContextIdentifier, WTFMove(message), sourceServiceWorker->data(), sourceOrigin }); |
| 255 | } |
| 256 | |
| 257 | void WebSWServerConnection::matchRegistration(uint64_t registrationMatchRequestIdentifier, const SecurityOriginData& topOrigin, const URL& clientURL) |
| 258 | { |
| 259 | if (auto* registration = doRegistrationMatching(topOrigin, clientURL)) { |
| 260 | send(Messages::WebSWClientConnection::DidMatchRegistration { registrationMatchRequestIdentifier, registration->data() }); |
| 261 | return; |
| 262 | } |
| 263 | send(Messages::WebSWClientConnection::DidMatchRegistration { registrationMatchRequestIdentifier, WTF::nullopt }); |
| 264 | } |
| 265 | |
| 266 | void WebSWServerConnection::registrationReady(uint64_t registrationReadyRequestIdentifier, ServiceWorkerRegistrationData&& registrationData) |
| 267 | { |
| 268 | send(Messages::WebSWClientConnection::RegistrationReady { registrationReadyRequestIdentifier, WTFMove(registrationData) }); |
| 269 | } |
| 270 | |
| 271 | void WebSWServerConnection::getRegistrations(uint64_t registrationMatchRequestIdentifier, const SecurityOriginData& topOrigin, const URL& clientURL) |
| 272 | { |
| 273 | auto registrations = server().getRegistrations(topOrigin, clientURL); |
| 274 | send(Messages::WebSWClientConnection::DidGetRegistrations { registrationMatchRequestIdentifier, registrations }); |
| 275 | } |
| 276 | |
| 277 | void WebSWServerConnection::registerServiceWorkerClient(SecurityOriginData&& topOrigin, ServiceWorkerClientData&& data, const Optional<ServiceWorkerRegistrationIdentifier>& controllingServiceWorkerRegistrationIdentifier, String&& userAgent) |
| 278 | { |
| 279 | auto clientOrigin = ClientOrigin { WTFMove(topOrigin), SecurityOriginData::fromURL(data.url) }; |
| 280 | m_clientOrigins.add(data.identifier, clientOrigin); |
| 281 | server().registerServiceWorkerClient(WTFMove(clientOrigin), WTFMove(data), controllingServiceWorkerRegistrationIdentifier, WTFMove(userAgent)); |
| 282 | |
| 283 | if (!m_isThrottleable) |
| 284 | updateThrottleState(); |
| 285 | } |
| 286 | |
| 287 | void WebSWServerConnection::unregisterServiceWorkerClient(const ServiceWorkerClientIdentifier& clientIdentifier) |
| 288 | { |
| 289 | auto iterator = m_clientOrigins.find(clientIdentifier); |
| 290 | if (iterator == m_clientOrigins.end()) |
| 291 | return; |
| 292 | |
| 293 | server().unregisterServiceWorkerClient(iterator->value, clientIdentifier); |
| 294 | m_clientOrigins.remove(iterator); |
| 295 | |
| 296 | if (!m_isThrottleable) |
| 297 | updateThrottleState(); |
| 298 | } |
| 299 | |
| 300 | bool WebSWServerConnection::hasMatchingClient(const RegistrableDomain& domain) const |
| 301 | { |
| 302 | return WTF::anyOf(m_clientOrigins.values(), [&domain](auto& origin) { |
| 303 | return domain.matches(origin.clientOrigin); |
| 304 | }); |
| 305 | } |
| 306 | |
| 307 | bool WebSWServerConnection::computeThrottleState(const RegistrableDomain& domain) const |
| 308 | { |
| 309 | return WTF::allOf(server().connections().values(), [&domain](auto& serverConnection) { |
| 310 | auto& connection = static_cast<WebSWServerConnection&>(*serverConnection); |
| 311 | return connection.isThrottleable() || !connection.hasMatchingClient(domain); |
| 312 | }); |
| 313 | } |
| 314 | |
| 315 | void WebSWServerConnection::setThrottleState(bool isThrottleable) |
| 316 | { |
| 317 | m_isThrottleable = isThrottleable; |
| 318 | updateThrottleState(); |
| 319 | } |
| 320 | |
| 321 | void WebSWServerConnection::updateThrottleState() |
| 322 | { |
| 323 | HashSet<SecurityOriginData> origins; |
| 324 | for (auto& origin : m_clientOrigins.values()) |
| 325 | origins.add(origin.clientOrigin); |
| 326 | |
| 327 | for (auto& origin : origins) { |
| 328 | if (auto* contextConnection = SWServerToContextConnection::connectionForRegistrableDomain(RegistrableDomain { origin })) { |
| 329 | auto& connection = static_cast<WebSWServerToContextConnection&>(*contextConnection); |
| 330 | |
| 331 | if (connection.isThrottleable() == m_isThrottleable) |
| 332 | continue; |
| 333 | bool newThrottleState = computeThrottleState(connection.registrableDomain()); |
| 334 | if (connection.isThrottleable() == newThrottleState) |
| 335 | continue; |
| 336 | connection.setThrottleState(newThrottleState); |
| 337 | } |
| 338 | } |
| 339 | } |
| 340 | |
| 341 | void WebSWServerConnection::serverToContextConnectionCreated(WebCore::SWServerToContextConnection& contextConnection) |
| 342 | { |
| 343 | auto& connection = static_cast<WebSWServerToContextConnection&>(contextConnection); |
| 344 | connection.setThrottleState(computeThrottleState(connection.registrableDomain())); |
| 345 | } |
| 346 | |
| 347 | void WebSWServerConnection::syncTerminateWorkerFromClient(WebCore::ServiceWorkerIdentifier&& identifier, CompletionHandler<void()>&& completionHandler) |
| 348 | { |
| 349 | syncTerminateWorker(WTFMove(identifier)); |
| 350 | completionHandler(); |
| 351 | } |
| 352 | |
| 353 | template<typename U> void WebSWServerConnection::sendToContextProcess(WebCore::SWServerToContextConnection& connection, U&& message) |
| 354 | { |
| 355 | static_cast<WebSWServerToContextConnection&>(connection).send(WTFMove(message)); |
| 356 | } |
| 357 | |
| 358 | } // namespace WebKit |
| 359 | |
| 360 | #endif // ENABLE(SERVICE_WORKER) |
| 361 | |