1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
|
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_HOST_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_HOST_H_
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/common/request_context_frame_type.h"
#include "content/public/common/request_context_type.h"
#include "content/public/common/resource_type.h"
namespace storage {
class BlobStorageContext;
}
namespace content {
class ResourceRequestBodyImpl;
class ServiceWorkerContextCore;
class ServiceWorkerDispatcherHost;
class ServiceWorkerRequestHandler;
class ServiceWorkerVersion;
class WebContents;
// This class is the browser-process representation of a service worker
// provider. There are two general types of providers: 1) those for a client
// (windows, dedicated workers, or shared workers), and 2) those for hosting a
// running service worker.
//
// For client providers, there is a provider per document or a worker and the
// lifetime of this object is tied to the lifetime of its document or the worker
// in the renderer process. This class holds service worker state that is scoped
// to an individual document or a worker.
//
// For providers hosting a running service worker, this class will observe
// resource loads made directly by the service worker.
class CONTENT_EXPORT ServiceWorkerProviderHost
: public NON_EXPORTED_BASE(ServiceWorkerRegistration::Listener),
public base::SupportsWeakPtr<ServiceWorkerProviderHost> {
public:
using GetRegistrationForReadyCallback =
base::Callback<void(ServiceWorkerRegistration* reigstration)>;
using WebContentsGetter = base::Callback<WebContents*(void)>;
// PlzNavigate
// Used to pre-create a ServiceWorkerProviderHost for a navigation. The
// ServiceWorkerNetworkProvider will later be created in the renderer, should
// the navigation succeed. |is_parent_frame_is_secure| should be true for main
// frames. Otherwise it is true iff all ancestor frames of this frame have a
// secure origin. |web_contents_getter| indicates the tab where the navigation
// is occurring.
static std::unique_ptr<ServiceWorkerProviderHost> PreCreateNavigationHost(
base::WeakPtr<ServiceWorkerContextCore> context,
bool are_ancestors_secure,
const WebContentsGetter& web_contents_getter);
enum class FrameSecurityLevel { UNINITIALIZED, INSECURE, SECURE };
// When this provider host is for a Service Worker context, |route_id| is
// MSG_ROUTING_NONE. When this provider host is for a Document,
// |route_id| is the frame ID of the Document. When this provider host is for
// a Shared Worker, |route_id| is the Shared Worker route ID.
// |provider_type| gives additional information whether the provider is
// created for controller (ServiceWorker) or controllee (Document or
// SharedWorker).
ServiceWorkerProviderHost(int render_process_id,
int route_id,
int provider_id,
ServiceWorkerProviderType provider_type,
FrameSecurityLevel parent_frame_security_level,
base::WeakPtr<ServiceWorkerContextCore> context,
ServiceWorkerDispatcherHost* dispatcher_host);
virtual ~ServiceWorkerProviderHost();
const std::string& client_uuid() const { return client_uuid_; }
int process_id() const { return render_process_id_; }
int provider_id() const { return provider_id_; }
int frame_id() const;
int route_id() const { return route_id_; }
const WebContentsGetter& web_contents_getter() const {
return web_contents_getter_;
}
bool is_parent_frame_secure() const {
return parent_frame_security_level_ == FrameSecurityLevel::SECURE;
}
void set_parent_frame_secure(bool is_parent_frame_secure) {
CHECK_EQ(parent_frame_security_level_, FrameSecurityLevel::UNINITIALIZED);
parent_frame_security_level_ = is_parent_frame_secure
? FrameSecurityLevel::SECURE
: FrameSecurityLevel::INSECURE;
}
// Returns whether this provider host is secure enough to have a service
// worker controller.
// Analogous to Blink's Document::isSecureContext. Because of how service
// worker intercepts main resource requests, this check must be done
// browser-side once the URL is known (see comments in
// ServiceWorkerNetworkProvider::CreateForNavigation). This function uses
// |document_url_| and |is_parent_frame_secure_| to determine context
// security, so they must be set properly before calling this function.
bool IsContextSecureForServiceWorker() const;
bool IsHostToRunningServiceWorker() {
return running_hosted_version_.get() != NULL;
}
// Returns this provider's controller. The controller is typically the same as
// active_version() but can differ in the following cases:
// (1) The client was created before the registration existed or had an active
// version (in spec language, it is not "using" the registration).
// (2) The client had a controller but NotifyControllerLost() was called due
// to an exceptional circumstance (here also it is not "using" the
// registration).
// (3) During algorithms such as the update, skipWaiting(), and claim() steps,
// the active_version and controlling_version may temporarily differ. For
// example, to perform skipWaiting(), the registration's active version is
// updated first and then the provider host's controlling version is updated
// to match it.
ServiceWorkerVersion* controlling_version() const {
// Only clients can have controllers.
DCHECK(!controlling_version_ || IsProviderForClient());
return controlling_version_.get();
}
ServiceWorkerVersion* active_version() const {
return associated_registration_.get() ?
associated_registration_->active_version() : NULL;
}
ServiceWorkerVersion* waiting_version() const {
return associated_registration_.get() ?
associated_registration_->waiting_version() : NULL;
}
ServiceWorkerVersion* installing_version() const {
return associated_registration_.get() ?
associated_registration_->installing_version() : NULL;
}
// Returns the associated registration. The provider host listens to this
// registration to resolve the .ready promise and set its controller.
ServiceWorkerRegistration* associated_registration() const {
// Only clients can have an associated registration.
DCHECK(!associated_registration_ || IsProviderForClient());
return associated_registration_.get();
}
// The running version, if any, that this provider is providing resource
// loads for.
ServiceWorkerVersion* running_hosted_version() const {
// Only providers for controllers can host a running version.
DCHECK(!running_hosted_version_ ||
provider_type_ == SERVICE_WORKER_PROVIDER_FOR_CONTROLLER);
return running_hosted_version_.get();
}
// Sets the |document_url_|. When this object is for a client,
// |matching_registrations_| gets also updated to ensure that |document_url_|
// is in scope of all |matching_registrations_|.
void SetDocumentUrl(const GURL& url);
const GURL& document_url() const { return document_url_; }
void SetTopmostFrameUrl(const GURL& url);
const GURL& topmost_frame_url() const { return topmost_frame_url_; }
ServiceWorkerProviderType provider_type() const { return provider_type_; }
bool IsProviderForClient() const;
blink::WebServiceWorkerClientType client_type() const;
// Associates to |registration| to listen for its version change events and
// sets the controller. If |notify_controllerchange| is true, instructs the
// renderer to dispatch a 'controllerchange' event.
void AssociateRegistration(ServiceWorkerRegistration* registration,
bool notify_controllerchange);
// Clears the associated registration and stop listening to it.
void DisassociateRegistration();
void SetHostedVersion(ServiceWorkerVersion* version);
// Returns a handler for a request, the handler may return NULL if
// the request doesn't require special handling.
std::unique_ptr<ServiceWorkerRequestHandler> CreateRequestHandler(
FetchRequestMode request_mode,
FetchCredentialsMode credentials_mode,
FetchRedirectMode redirect_mode,
ResourceType resource_type,
RequestContextType request_context_type,
RequestContextFrameType frame_type,
base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
scoped_refptr<ResourceRequestBodyImpl> body,
bool skip_service_worker);
// Used to get a ServiceWorkerObjectInfo to send to the renderer. Finds an
// existing ServiceWorkerHandle, and increments its reference count, or else
// creates a new one (initialized to ref count 1). Returns the
// ServiceWorkerInfo from the handle. The renderer is expected to use
// ServiceWorkerHandleReference::Adopt to balance out the ref count.
ServiceWorkerObjectInfo GetOrCreateServiceWorkerHandle(
ServiceWorkerVersion* version);
// Returns true if |registration| can be associated with this provider.
bool CanAssociateRegistration(ServiceWorkerRegistration* registration);
// For use by the ServiceWorkerControlleeRequestHandler to disallow
// new registration association while a navigation is occurring and
// an existing registration is being looked for.
void SetAllowAssociation(bool allow) { allow_association_ = allow; }
// Returns true if the context referred to by this host (i.e. |context_|) is
// still alive.
bool IsContextAlive();
// Dispatches message event to the document.
void PostMessageToClient(ServiceWorkerVersion* version,
const base::string16& message,
const std::vector<int>& sent_message_ports);
// Adds reference of this host's process to the |pattern|, the reference will
// be removed in destructor.
void AddScopedProcessReferenceToPattern(const GURL& pattern);
// |registration| claims the document to be controlled.
void ClaimedByRegistration(ServiceWorkerRegistration* registration);
// Called by dispatcher host to get the registration for the "ready" property.
// Returns false if there's a completed or ongoing request for the document.
// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#navigator-service-worker-ready
bool GetRegistrationForReady(const GetRegistrationForReadyCallback& callback);
// Methods to support cross site navigations.
void PrepareForCrossSiteTransfer();
void CompleteCrossSiteTransfer(
int new_process_id,
int new_frame_id,
int new_provider_id,
ServiceWorkerProviderType new_provider_type,
ServiceWorkerDispatcherHost* dispatcher_host);
ServiceWorkerDispatcherHost* dispatcher_host() const {
return dispatcher_host_;
}
// PlzNavigate
// Completes initialization of provider hosts used for navigation requests.
void CompleteNavigationInitialized(
int process_id,
int frame_routing_id,
ServiceWorkerDispatcherHost* dispatcher_host);
// Sends event messages to the renderer. Events for the worker are queued up
// until the worker thread id is known via SetReadyToSendMessagesToWorker().
void SendUpdateFoundMessage(
int registration_handle_id);
void SendSetVersionAttributesMessage(
int registration_handle_id,
ChangedVersionAttributesMask changed_mask,
ServiceWorkerVersion* installing_version,
ServiceWorkerVersion* waiting_version,
ServiceWorkerVersion* active_version);
void SendServiceWorkerStateChangedMessage(
int worker_handle_id,
blink::WebServiceWorkerState state);
// Sets the worker thread id and flushes queued events.
void SetReadyToSendMessagesToWorker(int render_thread_id);
void AddMatchingRegistration(ServiceWorkerRegistration* registration);
void RemoveMatchingRegistration(ServiceWorkerRegistration* registration);
// An optimized implementation of [[Match Service Worker Registration]]
// for current document.
ServiceWorkerRegistration* MatchRegistration() const;
// Called when our controller has been terminated and doomed due to an
// exceptional condition like it could no longer be read from the script
// cache.
void NotifyControllerLost();
private:
friend class ForeignFetchRequestHandlerTest;
friend class LinkHeaderServiceWorkerTest;
friend class ServiceWorkerProviderHostTest;
friend class ServiceWorkerWriteToCacheJobTest;
friend class ServiceWorkerContextRequestHandlerTest;
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest, Update_SameScript);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest,
Update_SameSizeScript);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest,
Update_TruncatedScript);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest,
Update_ElongatedScript);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest,
Update_EmptyScript);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDispatcherHostTest,
DispatchExtendableMessageEvent);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDispatcherHostTest,
DispatchExtendableMessageEvent_Fail);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerProviderHostTest, ContextSecurity);
struct OneShotGetReadyCallback {
GetRegistrationForReadyCallback callback;
bool called;
explicit OneShotGetReadyCallback(
const GetRegistrationForReadyCallback& callback);
~OneShotGetReadyCallback();
};
// ServiceWorkerRegistration::Listener overrides.
void OnVersionAttributesChanged(
ServiceWorkerRegistration* registration,
ChangedVersionAttributesMask changed_mask,
const ServiceWorkerRegistrationInfo& info) override;
void OnRegistrationFailed(ServiceWorkerRegistration* registration) override;
void OnRegistrationFinishedUninstalling(
ServiceWorkerRegistration* registration) override;
void OnSkippedWaiting(ServiceWorkerRegistration* registration) override;
// Sets the controller version field to |version| or if |version| is NULL,
// clears the field. If |notify_controllerchange| is true, instructs the
// renderer to dispatch a 'controller' change event.
void SetControllerVersionAttribute(ServiceWorkerVersion* version,
bool notify_controllerchange);
void SendAssociateRegistrationMessage();
// Syncs matching registrations with live registrations.
void SyncMatchingRegistrations();
// Discards all references to matching registrations.
void RemoveAllMatchingRegistrations();
// Increase/decrease this host's process reference for |pattern|.
void IncreaseProcessReference(const GURL& pattern);
void DecreaseProcessReference(const GURL& pattern);
void ReturnRegistrationForReadyIfNeeded();
bool IsReadyToSendMessages() const;
void Send(IPC::Message* message) const;
// Finalizes cross-site transfers and navigation-initalized hosts.
void FinalizeInitialization(int process_id,
int frame_routing_id,
ServiceWorkerDispatcherHost* dispatcher_host);
std::string client_uuid_;
int render_process_id_;
// See the constructor's documentation.
int route_id_;
// For provider hosts that are hosting a running service worker, the id of the
// service worker thread. Otherwise, |kDocumentMainThreadId|. May be
// |kInvalidEmbeddedWorkerThreadId| before the hosted service worker starts
// up, or during cross-site transfers.
int render_thread_id_;
// Unique within the renderer process.
int provider_id_;
// PlzNavigate
// Only set when this object is pre-created for a navigation. It indicates the
// tab where the navigation occurs.
WebContentsGetter web_contents_getter_;
ServiceWorkerProviderType provider_type_;
FrameSecurityLevel parent_frame_security_level_;
GURL document_url_;
GURL topmost_frame_url_;
std::vector<GURL> associated_patterns_;
scoped_refptr<ServiceWorkerRegistration> associated_registration_;
// Keyed by registration scope URL length.
typedef std::map<size_t, scoped_refptr<ServiceWorkerRegistration>>
ServiceWorkerRegistrationMap;
// Contains all living registrations whose pattern this document's URL
// starts with. It is empty if IsContextSecureForServiceWorker() is
// false.
ServiceWorkerRegistrationMap matching_registrations_;
std::unique_ptr<OneShotGetReadyCallback> get_ready_callback_;
scoped_refptr<ServiceWorkerVersion> controlling_version_;
scoped_refptr<ServiceWorkerVersion> running_hosted_version_;
base::WeakPtr<ServiceWorkerContextCore> context_;
ServiceWorkerDispatcherHost* dispatcher_host_;
bool allow_association_;
std::vector<base::Closure> queued_events_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderHost);
};
} // namespace content
#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_HOST_H_
|