| // Copyright 2017 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. |
| |
| #include "content/renderer/service_worker/worker_fetch_context_impl.h" |
| |
| #include "base/feature_list.h" |
| #include "content/child/child_thread_impl.h" |
| #include "content/child/thread_safe_sender.h" |
| #include "content/common/frame_messages.h" |
| #include "content/common/service_worker/service_worker_utils.h" |
| #include "content/common/wrapper_shared_url_loader_factory.h" |
| #include "content/public/common/content_features.h" |
| #include "content/public/common/service_names.mojom.h" |
| #include "content/public/renderer/url_loader_throttle_provider.h" |
| #include "content/renderer/loader/request_extra_data.h" |
| #include "content/renderer/loader/resource_dispatcher.h" |
| #include "content/renderer/loader/web_url_loader_impl.h" |
| #include "content/renderer/loader/web_url_request_util.h" |
| #include "content/renderer/service_worker/controller_service_worker_connector.h" |
| #include "content/renderer/service_worker/service_worker_subresource_loader.h" |
| #include "mojo/public/cpp/bindings/binding.h" |
| #include "mojo/public/cpp/bindings/strong_binding.h" |
| #include "services/service_manager/public/cpp/connector.h" |
| #include "third_party/WebKit/common/service_worker/service_worker_object.mojom.h" |
| |
| namespace content { |
| |
| class WorkerFetchContextImpl::URLLoaderFactoryImpl |
| : public blink::WebURLLoaderFactory { |
| public: |
| URLLoaderFactoryImpl(base::WeakPtr<ResourceDispatcher> resource_dispatcher, |
| scoped_refptr<SharedURLLoaderFactory> loader_factory) |
| : resource_dispatcher_(std::move(resource_dispatcher)), |
| loader_factory_(std::move(loader_factory)), |
| weak_ptr_factory_(this) {} |
| ~URLLoaderFactoryImpl() override = default; |
| |
| std::unique_ptr<blink::WebURLLoader> CreateURLLoader( |
| const blink::WebURLRequest& request, |
| scoped_refptr<base::SingleThreadTaskRunner> task_runner) override { |
| DCHECK(task_runner); |
| DCHECK(resource_dispatcher_); |
| if (auto loader = CreateServiceWorkerURLLoader(request, task_runner)) |
| return loader; |
| return std::make_unique<WebURLLoaderImpl>( |
| resource_dispatcher_.get(), std::move(task_runner), loader_factory_); |
| } |
| |
| void SetServiceWorkerURLLoaderFactory( |
| network::mojom::URLLoaderFactoryPtr service_worker_url_loader_factory) { |
| service_worker_url_loader_factory_ = |
| base::MakeRefCounted<WrapperSharedURLLoaderFactory>( |
| std::move(service_worker_url_loader_factory)); |
| } |
| |
| base::WeakPtr<URLLoaderFactoryImpl> GetWeakPtr() { |
| return weak_ptr_factory_.GetWeakPtr(); |
| } |
| |
| private: |
| std::unique_ptr<blink::WebURLLoader> CreateServiceWorkerURLLoader( |
| const blink::WebURLRequest& request, |
| scoped_refptr<base::SingleThreadTaskRunner> task_runner) { |
| // TODO(horo): Unify this code path with |
| // ServiceWorkerNetworkProvider::CreateURLLoader that is used for document |
| // cases. |
| |
| // We need URLLoaderFactory populated in order to create our own URLLoader |
| // for subresource loading via a service worker. |
| if (!service_worker_url_loader_factory_) |
| return nullptr; |
| |
| // If it's not for HTTP or HTTPS no need to intercept the request. |
| if (!GURL(request.Url()).SchemeIsHTTPOrHTTPS()) |
| return nullptr; |
| |
| // If the service worker mode is not all, no need to intercept the request. |
| if (request.GetServiceWorkerMode() != |
| blink::WebURLRequest::ServiceWorkerMode::kAll) { |
| return nullptr; |
| } |
| |
| // Create our own URLLoader to route the request to the controller service |
| // worker. |
| return std::make_unique<WebURLLoaderImpl>( |
| resource_dispatcher_.get(), std::move(task_runner), |
| service_worker_url_loader_factory_); |
| } |
| |
| base::WeakPtr<ResourceDispatcher> resource_dispatcher_; |
| scoped_refptr<SharedURLLoaderFactory> loader_factory_; |
| scoped_refptr<SharedURLLoaderFactory> service_worker_url_loader_factory_; |
| base::WeakPtrFactory<URLLoaderFactoryImpl> weak_ptr_factory_; |
| DISALLOW_COPY_AND_ASSIGN(URLLoaderFactoryImpl); |
| }; |
| |
| WorkerFetchContextImpl::WorkerFetchContextImpl( |
| mojom::ServiceWorkerWorkerClientRequest service_worker_client_request, |
| mojom::ServiceWorkerContainerHostPtrInfo service_worker_container_host_info, |
| std::unique_ptr<SharedURLLoaderFactoryInfo> url_loader_factory_info, |
| std::unique_ptr<SharedURLLoaderFactoryInfo> direct_network_factory_info, |
| std::unique_ptr<URLLoaderThrottleProvider> throttle_provider) |
| : binding_(this), |
| service_worker_client_request_(std::move(service_worker_client_request)), |
| service_worker_container_host_info_( |
| std::move(service_worker_container_host_info)), |
| url_loader_factory_info_(std::move(url_loader_factory_info)), |
| direct_network_loader_factory_info_( |
| std::move(direct_network_factory_info)), |
| thread_safe_sender_(ChildThreadImpl::current()->thread_safe_sender()), |
| throttle_provider_(std::move(throttle_provider)) { |
| if (ServiceWorkerUtils::IsServicificationEnabled()) { |
| ChildThreadImpl::current()->GetConnector()->BindInterface( |
| mojom::kBrowserServiceName, |
| mojo::MakeRequest(&blob_registry_ptr_info_)); |
| } |
| } |
| |
| WorkerFetchContextImpl::~WorkerFetchContextImpl() {} |
| |
| void WorkerFetchContextImpl::InitializeOnWorkerThread() { |
| DCHECK(!resource_dispatcher_); |
| DCHECK(!binding_.is_bound()); |
| resource_dispatcher_ = std::make_unique<ResourceDispatcher>(); |
| |
| shared_url_loader_factory_ = |
| SharedURLLoaderFactory::Create(std::move(url_loader_factory_info_)); |
| direct_network_loader_factory_ = SharedURLLoaderFactory::Create( |
| std::move(direct_network_loader_factory_info_)); |
| if (service_worker_client_request_.is_pending()) |
| binding_.Bind(std::move(service_worker_client_request_)); |
| |
| if (ServiceWorkerUtils::IsServicificationEnabled()) { |
| service_worker_container_host_.Bind( |
| std::move(service_worker_container_host_info_)); |
| |
| blink::mojom::BlobRegistryPtr blob_registry_ptr; |
| blob_registry_ptr.Bind(std::move(blob_registry_ptr_info_)); |
| blob_registry_ = base::MakeRefCounted< |
| base::RefCountedData<blink::mojom::BlobRegistryPtr>>( |
| std::move(blob_registry_ptr)); |
| } |
| } |
| |
| std::unique_ptr<blink::WebURLLoaderFactory> |
| WorkerFetchContextImpl::CreateURLLoaderFactory() { |
| DCHECK(shared_url_loader_factory_); |
| DCHECK(!url_loader_factory_); |
| auto factory = std::make_unique<URLLoaderFactoryImpl>( |
| resource_dispatcher_->GetWeakPtr(), shared_url_loader_factory_); |
| url_loader_factory_ = factory->GetWeakPtr(); |
| |
| if (ServiceWorkerUtils::IsServicificationEnabled()) |
| ResetServiceWorkerURLLoaderFactory(); |
| |
| return factory; |
| } |
| |
| std::unique_ptr<blink::WebURLLoaderFactory> |
| WorkerFetchContextImpl::WrapURLLoaderFactory( |
| mojo::ScopedMessagePipeHandle url_loader_factory_handle) { |
| return std::make_unique<content::WebURLLoaderFactoryImpl>( |
| resource_dispatcher_->GetWeakPtr(), |
| base::MakeRefCounted<WrapperSharedURLLoaderFactory>( |
| network::mojom::URLLoaderFactoryPtrInfo( |
| std::move(url_loader_factory_handle), |
| network::mojom::URLLoaderFactory::Version_))); |
| } |
| |
| void WorkerFetchContextImpl::WillSendRequest(blink::WebURLRequest& request) { |
| RequestExtraData* extra_data = new RequestExtraData(); |
| extra_data->set_service_worker_provider_id(service_worker_provider_id_); |
| extra_data->set_render_frame_id(parent_frame_id_); |
| extra_data->set_initiated_in_secure_context(is_secure_context_); |
| if (throttle_provider_) { |
| extra_data->set_url_loader_throttles(throttle_provider_->CreateThrottles( |
| parent_frame_id_, request.Url(), WebURLRequestToResourceType(request))); |
| } |
| request.SetExtraData(extra_data); |
| request.SetAppCacheHostID(appcache_host_id_); |
| |
| if (!IsControlledByServiceWorker() && |
| request.GetServiceWorkerMode() != |
| blink::WebURLRequest::ServiceWorkerMode::kNone) { |
| // TODO(falken): Is still this needed? It used to set kForeign for foreign |
| // fetch. |
| request.SetServiceWorkerMode( |
| blink::WebURLRequest::ServiceWorkerMode::kNone); |
| } |
| } |
| |
| bool WorkerFetchContextImpl::IsControlledByServiceWorker() const { |
| return is_controlled_by_service_worker_ || |
| (controller_version_id_ != |
| blink::mojom::kInvalidServiceWorkerVersionId); |
| } |
| |
| void WorkerFetchContextImpl::SetIsOnSubframe(bool is_on_sub_frame) { |
| is_on_sub_frame_ = is_on_sub_frame; |
| } |
| |
| bool WorkerFetchContextImpl::IsOnSubframe() const { |
| return is_on_sub_frame_; |
| } |
| |
| blink::WebURL WorkerFetchContextImpl::SiteForCookies() const { |
| return site_for_cookies_; |
| } |
| |
| void WorkerFetchContextImpl::DidRunContentWithCertificateErrors() { |
| Send(new FrameHostMsg_DidRunContentWithCertificateErrors(parent_frame_id_)); |
| } |
| |
| void WorkerFetchContextImpl::DidDisplayContentWithCertificateErrors() { |
| Send(new FrameHostMsg_DidDisplayContentWithCertificateErrors( |
| parent_frame_id_)); |
| } |
| |
| void WorkerFetchContextImpl::DidRunInsecureContent( |
| const blink::WebSecurityOrigin& origin, |
| const blink::WebURL& url) { |
| Send(new FrameHostMsg_DidRunInsecureContent( |
| parent_frame_id_, GURL(origin.ToString().Utf8()), url)); |
| } |
| |
| void WorkerFetchContextImpl::SetSubresourceFilterBuilder( |
| std::unique_ptr<blink::WebDocumentSubresourceFilter::Builder> |
| subresource_filter_builder) { |
| subresource_filter_builder_ = std::move(subresource_filter_builder); |
| } |
| |
| std::unique_ptr<blink::WebDocumentSubresourceFilter> |
| WorkerFetchContextImpl::TakeSubresourceFilter() { |
| if (!subresource_filter_builder_) |
| return nullptr; |
| return std::move(subresource_filter_builder_)->Build(); |
| } |
| |
| void WorkerFetchContextImpl::set_service_worker_provider_id(int id) { |
| service_worker_provider_id_ = id; |
| } |
| |
| void WorkerFetchContextImpl::set_is_controlled_by_service_worker(bool flag) { |
| is_controlled_by_service_worker_ = flag; |
| } |
| |
| void WorkerFetchContextImpl::set_parent_frame_id(int id) { |
| parent_frame_id_ = id; |
| } |
| |
| void WorkerFetchContextImpl::set_site_for_cookies( |
| const blink::WebURL& site_for_cookies) { |
| site_for_cookies_ = site_for_cookies; |
| } |
| |
| void WorkerFetchContextImpl::set_is_secure_context(bool flag) { |
| is_secure_context_ = flag; |
| } |
| |
| void WorkerFetchContextImpl::set_origin_url(const GURL& origin_url) { |
| origin_url_ = origin_url; |
| } |
| |
| void WorkerFetchContextImpl::SetApplicationCacheHostID(int id) { |
| appcache_host_id_ = id; |
| } |
| |
| int WorkerFetchContextImpl::ApplicationCacheHostID() const { |
| return appcache_host_id_; |
| } |
| |
| void WorkerFetchContextImpl::SetControllerServiceWorker( |
| int64_t controller_version_id) { |
| controller_version_id_ = controller_version_id; |
| if (ServiceWorkerUtils::IsServicificationEnabled()) |
| ResetServiceWorkerURLLoaderFactory(); |
| } |
| |
| bool WorkerFetchContextImpl::Send(IPC::Message* message) { |
| return thread_safe_sender_->Send(message); |
| } |
| |
| void WorkerFetchContextImpl::ResetServiceWorkerURLLoaderFactory() { |
| DCHECK(ServiceWorkerUtils::IsServicificationEnabled()); |
| if (!url_loader_factory_) |
| return; |
| if (!IsControlledByServiceWorker()) { |
| url_loader_factory_->SetServiceWorkerURLLoaderFactory(nullptr); |
| return; |
| } |
| network::mojom::URLLoaderFactoryPtr service_worker_url_loader_factory; |
| mojo::MakeStrongBinding( |
| std::make_unique<ServiceWorkerSubresourceLoaderFactory>( |
| base::MakeRefCounted<ControllerServiceWorkerConnector>( |
| service_worker_container_host_.get()), |
| direct_network_loader_factory_), |
| mojo::MakeRequest(&service_worker_url_loader_factory)); |
| url_loader_factory_->SetServiceWorkerURLLoaderFactory( |
| std::move(service_worker_url_loader_factory)); |
| } |
| |
| } // namespace content |