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
|
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/service_worker/service_worker_main_resource_handle.h"
#include <utility>
#include "base/functional/bind.h"
#include "content/browser/preloading/prefetch/prefetch_features.h"
#include "content/browser/renderer_host/policy_container_host.h"
#include "content/browser/service_worker/service_worker_client.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/global_routing_id.h"
#include "net/base/isolation_info.h"
#include "net/base/url_util.h"
#include "net/cookies/site_for_cookies.h"
#include "services/network/public/cpp/cross_origin_embedder_policy.h"
namespace content {
ServiceWorkerMainResourceHandle::ServiceWorkerMainResourceHandle(
scoped_refptr<ServiceWorkerContextWrapper> context_wrapper,
ServiceWorkerAccessedCallback on_service_worker_accessed,
std::string fetch_event_client_id,
base::WeakPtr<ServiceWorkerClient> parent_service_worker_client)
: parent_service_worker_client_(std::move(parent_service_worker_client)),
fetch_event_client_id_(std::move(fetch_event_client_id)),
service_worker_accessed_callback_(std::move(on_service_worker_accessed)),
context_wrapper_(std::move(context_wrapper)) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
ServiceWorkerMainResourceHandle::~ServiceWorkerMainResourceHandle() = default;
void ServiceWorkerMainResourceHandle::set_service_worker_client(
ScopedServiceWorkerClient scoped_service_worker_client,
const net::IsolationInfo& isolation_info) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
CHECK(!scoped_service_worker_client_);
scoped_service_worker_client_ = std::make_unique<ScopedServiceWorkerClient>(
std::move(scoped_service_worker_client));
isolation_info_ = isolation_info;
CHECK(service_worker_client());
}
base::WeakPtr<ServiceWorkerClient>
ServiceWorkerMainResourceHandle::service_worker_client() {
if (!scoped_service_worker_client_) {
return nullptr;
}
return scoped_service_worker_client_->AsWeakPtr();
}
bool ServiceWorkerMainResourceHandle::InitializeForRequest(
const network::ResourceRequest& tentative_resource_request,
const ServiceWorkerClient* client_for_prefetch) {
CHECK(service_worker_client());
// Update `isolation_info_` to equal the net::IsolationInfo needed for any
// service worker intercepting this request. Here, `isolation_info_` directly
// corresponds to the StorageKey used to look up the service worker's
// registration. That StorageKey will then be used later to recreate this
// net::IsolationInfo for use by the ServiceWorker itself.
url::Origin new_origin = url::Origin::Create(tentative_resource_request.url);
net::SiteForCookies new_site_for_cookies = isolation_info_.site_for_cookies();
new_site_for_cookies.CompareWithFrameTreeOriginAndRevise(new_origin);
auto new_isolation_info = net::IsolationInfo::Create(
isolation_info_.request_type(),
isolation_info_.top_frame_origin().value(), new_origin,
new_site_for_cookies, isolation_info_.nonce());
// The storage key only has a top_level_site, not an origin, so we must
// extract the origin from trusted_params.
auto top_frame_origin = tentative_resource_request.trusted_params
? tentative_resource_request.trusted_params
->isolation_info.top_frame_origin()
: std::nullopt;
auto key = service_worker_client()->CalculateStorageKeyForUpdateUrls(
tentative_resource_request.url, new_isolation_info);
if (client_for_prefetch) {
CHECK(base::FeatureList::IsEnabled(features::kPrefetchServiceWorker));
CHECK(service_worker_client()->IsContainerForWindowClient());
CHECK(client_for_prefetch->IsContainerForWindowClient());
// If top_frame_origin/key don't match, do not use the prefetch result.
// `this` remains unmodified, and `InitializeForRequest` will be called
// later in the non-prefetch code path.
if (client_for_prefetch->top_frame_origin() != top_frame_origin ||
client_for_prefetch->key() != key) {
return false;
}
}
isolation_info_ = std::move(new_isolation_info);
// Clear old controller state if this is a redirect.
service_worker_client()->SetControllerRegistration(
nullptr,
/*notify_controllerchange=*/false);
// Update the service worker client. This is important to do this on every
// requests/redirects before falling back to network below, so service worker
// APIs still work even if the service worker is bypassed for request
// interception.
service_worker_client()->UpdateUrls(tentative_resource_request.url,
std::move(top_frame_origin),
std::move(key));
// Inherit the controller used for prefetching from `client_for_prefetch`.
if (client_for_prefetch && client_for_prefetch->controller_registration()) {
service_worker_client()->AddMatchingRegistration(
client_for_prefetch->controller_registration());
// `client_for_prefetch` shouldn't be in back forward cache because it's for
// prefetch.
CHECK(!client_for_prefetch->is_in_back_forward_cache());
service_worker_client()->SetControllerRegistration(
client_for_prefetch->controller_registration(),
/*notify_controllerchange=*/false);
}
return true;
}
} // namespace content
|