Index: third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp |
diff --git a/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp b/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp |
index a1ca5f31714127a3a48bfdc96d90dd9f33cc561a..843ffb43a25fe8182bdd1c989662a50383e0007f 100644 |
--- a/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp |
+++ b/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp |
@@ -4,13 +4,21 @@ |
#include "core/loader/WorkerFetchContext.h" |
+#include "core/loader/MixedContentChecker.h" |
+#include "core/probe/CoreProbes.h" |
+#include "core/timing/WorkerGlobalScopePerformance.h" |
#include "core/workers/WorkerClients.h" |
#include "core/workers/WorkerGlobalScope.h" |
+#include "platform/RuntimeEnabledFeatures.h" |
#include "platform/Supplementable.h" |
#include "platform/WebTaskRunner.h" |
#include "platform/exported/WrappedResourceRequest.h" |
+#include "platform/loader/fetch/ResourceFetcher.h" |
#include "platform/scheduler/child/web_scheduler.h" |
+#include "platform/weborigin/SecurityPolicy.h" |
#include "public/platform/Platform.h" |
+#include "public/platform/WebMixedContent.h" |
+#include "public/platform/WebMixedContentContextType.h" |
#include "public/platform/WebThread.h" |
#include "public/platform/WebWorkerFetchContext.h" |
@@ -50,13 +58,68 @@ class WorkerFetchContextHolder final |
} // namespace |
+class WorkerFetchContext::WorkerResourceCallback final |
+ : public GarbageCollectedFinalized<WorkerResourceCallback>, |
+ public Resource::ResourceCallback { |
+ public: |
+ WorkerResourceCallback(WebTaskRunner* loading_task_runner) |
+ : loading_task_runner_(loading_task_runner) {} |
+ ~WorkerResourceCallback() {} |
+ void Schedule(Resource*) override; |
+ void Cancel(Resource*) override; |
+ bool IsScheduled(Resource*) const override; |
+ DECLARE_TRACE(); |
+ |
+ private: |
+ void RunTask(); |
+ |
+ RefPtr<WebTaskRunner> loading_task_runner_; |
+ TaskHandle task_handle_; |
+ HeapHashSet<Member<Resource>> resources_with_pending_clients_; |
+}; |
+ |
+DEFINE_TRACE(WorkerFetchContext::WorkerResourceCallback) { |
+ visitor->Trace(resources_with_pending_clients_); |
+} |
+ |
+void WorkerFetchContext::WorkerResourceCallback::Schedule(Resource* resource) { |
+ if (!task_handle_.IsActive()) { |
+ task_handle_ = loading_task_runner_->PostCancellableTask( |
+ BLINK_FROM_HERE, |
+ WTF::Bind(&WorkerResourceCallback::RunTask, WrapWeakPersistent(this))); |
+ } |
+ resources_with_pending_clients_.insert(resource); |
+} |
+ |
+void WorkerFetchContext::WorkerResourceCallback::Cancel(Resource* resource) { |
+ resources_with_pending_clients_.erase(resource); |
+ if (task_handle_.IsActive() && resources_with_pending_clients_.IsEmpty()) |
+ task_handle_.Cancel(); |
+} |
+ |
+bool WorkerFetchContext::WorkerResourceCallback::IsScheduled( |
+ Resource* resource) const { |
+ return resources_with_pending_clients_.Contains(resource); |
+} |
+ |
+void WorkerFetchContext::WorkerResourceCallback::RunTask() { |
+ HeapVector<Member<Resource>> resources; |
+ for (const Member<Resource>& resource : resources_with_pending_clients_) |
+ resources.push_back(resource); |
+ resources_with_pending_clients_.clear(); |
+ |
+ for (const auto& resource : resources) |
+ resource->FinishPendingClients(); |
+} |
+ |
WorkerFetchContext::~WorkerFetchContext() {} |
WorkerFetchContext* WorkerFetchContext::Create( |
WorkerGlobalScope& worker_global_scope) { |
DCHECK(worker_global_scope.IsContextThread()); |
WorkerClients* worker_clients = worker_global_scope.Clients(); |
- DCHECK(worker_clients); |
+ if (!worker_clients) |
+ return nullptr; |
WorkerFetchContextHolder* holder = |
static_cast<WorkerFetchContextHolder*>(Supplement<WorkerClients>::From( |
*worker_clients, WorkerFetchContextHolder::SupplementName())); |
@@ -64,17 +127,31 @@ WorkerFetchContext* WorkerFetchContext::Create( |
return nullptr; |
std::unique_ptr<WebWorkerFetchContext> web_context = holder->TakeContext(); |
DCHECK(web_context); |
- return new WorkerFetchContext(std::move(web_context)); |
+ return new WorkerFetchContext(worker_global_scope, std::move(web_context)); |
} |
WorkerFetchContext::WorkerFetchContext( |
+ WorkerGlobalScope& worker_global_scope, |
std::unique_ptr<WebWorkerFetchContext> web_context) |
- : web_context_(std::move(web_context)) { |
- web_context_->InitializeOnWorkerThread(Platform::Current() |
- ->CurrentThread() |
- ->Scheduler() |
- ->LoadingTaskRunner() |
- ->ToSingleThreadTaskRunner()); |
+ : worker_global_scope_(worker_global_scope), |
+ web_context_(std::move(web_context)), |
+ loading_task_runner_(Platform::Current() |
+ ->CurrentThread() |
+ ->Scheduler() |
+ ->LoadingTaskRunner()), |
+ timer_task_runner_( |
+ Platform::Current()->CurrentThread()->Scheduler()->TimerTaskRunner()), |
+ resource_callback_( |
+ new WorkerResourceCallback(loading_task_runner_.Get())) { |
+ web_context_->InitializeOnWorkerThread( |
+ loading_task_runner_->ToSingleThreadTaskRunner()); |
+} |
+ |
+ResourceFetcher* WorkerFetchContext::GetResourceFetcher() { |
+ if (resource_fetcher_) |
+ return resource_fetcher_; |
+ resource_fetcher_ = ResourceFetcher::Create(this); |
+ return resource_fetcher_; |
} |
std::unique_ptr<WebURLLoader> WorkerFetchContext::CreateURLLoader() { |
@@ -85,12 +162,229 @@ bool WorkerFetchContext::IsControlledByServiceWorker() const { |
return web_context_->IsControlledByServiceWorker(); |
} |
+int64_t WorkerFetchContext::ServiceWorkerID() const { |
+ // TODO(horo): ServiceWorkerID() is used only for memory cache which is |
+ // disabled in worker thread. So we should remove this method. |
+ return web_context_->ServiceWorkerID(); |
+} |
+ |
+ResourceRequestBlockedReason WorkerFetchContext::CanRequest( |
+ Resource::Type type, |
+ const ResourceRequest& resource_request, |
+ const KURL& url, |
+ const ResourceLoaderOptions& options, |
+ SecurityViolationReportingPolicy reporting_policy, |
+ FetchParameters::OriginRestriction origin_restriction) const { |
+ ResourceRequestBlockedReason blocked_reason = CanRequestInternal( |
+ type, resource_request, url, options, reporting_policy, |
+ origin_restriction, resource_request.GetRedirectStatus()); |
+ if (blocked_reason != ResourceRequestBlockedReason::kNone) { |
+ probe::didBlockRequest(worker_global_scope_, resource_request, nullptr, |
+ options.initiator_info, blocked_reason); |
+ } |
+ return blocked_reason; |
+} |
+ |
+ResourceRequestBlockedReason WorkerFetchContext::CanFollowRedirect( |
+ Resource::Type type, |
+ const ResourceRequest& resource_request, |
+ const KURL& url, |
+ const ResourceLoaderOptions& options, |
+ SecurityViolationReportingPolicy reporting_policy, |
+ FetchParameters::OriginRestriction origin_restriction) const { |
+ ResourceRequestBlockedReason blocked_reason = CanRequestInternal( |
+ type, resource_request, url, options, reporting_policy, |
+ origin_restriction, resource_request.GetRedirectStatus()); |
+ if (blocked_reason != ResourceRequestBlockedReason::kNone) { |
+ probe::didBlockRequest(worker_global_scope_, resource_request, nullptr, |
+ options.initiator_info, blocked_reason); |
+ } |
+ return blocked_reason; |
+} |
+ |
+void WorkerFetchContext::AddAdditionalRequestHeaders(ResourceRequest& request, |
+ FetchResourceType type) { |
+ bool isMainResource = type == kFetchMainResource; |
+ if (!isMainResource) { |
+ if (!request.DidSetHTTPReferrer()) { |
+ request.SetHTTPReferrer(SecurityPolicy::GenerateReferrer( |
+ worker_global_scope_->GetReferrerPolicy(), request.Url(), |
+ worker_global_scope_->OutgoingReferrer())); |
+ request.AddHTTPOriginIfNeeded(worker_global_scope_->GetSecurityOrigin()); |
+ } else { |
+ DCHECK_EQ(SecurityPolicy::GenerateReferrer(request.GetReferrerPolicy(), |
+ request.Url(), |
+ request.HttpReferrer()) |
+ .referrer, |
+ request.HttpReferrer()); |
+ request.AddHTTPOriginIfNeeded(request.HttpReferrer()); |
+ } |
+ } |
+} |
+ |
void WorkerFetchContext::PrepareRequest(ResourceRequest& request, |
RedirectType) { |
+ String user_agent = worker_global_scope_->UserAgent(); |
+ probe::applyUserAgentOverride(worker_global_scope_, &user_agent); |
+ DCHECK(!user_agent.IsNull()); |
+ request.SetHTTPUserAgent(AtomicString(user_agent)); |
+ |
+ request.SetIsMojoIPCForced(true); |
+ if (request.RequestorOrigin()->IsUnique() && |
+ !worker_global_scope_->GetSecurityOrigin()->IsUnique()) { |
+ request.SetRequestorOrigin(worker_global_scope_->GetSecurityOrigin()); |
+ } |
WrappedResourceRequest webreq(request); |
web_context_->WillSendRequest(webreq); |
} |
+void WorkerFetchContext::DispatchWillSendRequest( |
+ unsigned long identifier, |
+ ResourceRequest& request, |
+ const ResourceResponse& redirect_response, |
+ const FetchInitiatorInfo& initiator_info) { |
+ probe::willSendRequest(worker_global_scope_, identifier, nullptr, request, |
+ redirect_response, initiator_info); |
+} |
+ |
+void WorkerFetchContext::DispatchDidReceiveResponse( |
+ unsigned long identifier, |
+ const ResourceResponse& response, |
+ WebURLRequest::FrameType frame_type, |
+ WebURLRequest::RequestContext request_context, |
+ Resource* resource, |
+ ResourceResponseType) { |
+ if (response.HasMajorCertificateErrors()) { |
+ WebMixedContentContextType context_type = |
+ WebMixedContent::ContextTypeFromRequestContext( |
+ request_context, false /* strictMixedContentCheckingForPlugin */); |
+ if (context_type == WebMixedContentContextType::kBlockable) { |
+ web_context_->DidRunContentWithCertificateErrors(response.Url()); |
+ } else { |
+ web_context_->DidDisplayContentWithCertificateErrors(response.Url()); |
+ } |
+ } |
+ probe::didReceiveResourceResponse(worker_global_scope_, identifier, nullptr, |
+ response, resource); |
+} |
+ |
+void WorkerFetchContext::DispatchDidReceiveData(unsigned long identifier, |
+ const char* data, |
+ int data_length) { |
+ probe::didReceiveData(worker_global_scope_, identifier, nullptr, data, |
+ data_length); |
+} |
+ |
+void WorkerFetchContext::DispatchDidReceiveEncodedData( |
+ unsigned long identifier, |
+ int encoded_data_length) { |
+ probe::didReceiveEncodedDataLength(worker_global_scope_, identifier, |
+ encoded_data_length); |
+} |
+ |
+void WorkerFetchContext::DispatchDidFinishLoading(unsigned long identifier, |
+ double finish_time, |
+ int64_t encoded_data_length, |
+ int64_t decoded_body_length) { |
+ probe::didFinishLoading(worker_global_scope_, identifier, nullptr, |
+ finish_time, encoded_data_length, |
+ decoded_body_length); |
+} |
+ |
+void WorkerFetchContext::DispatchDidFail(unsigned long identifier, |
+ const ResourceError& error, |
+ int64_t encoded_data_length, |
+ bool is_internal_request) { |
+ probe::didFailLoading(worker_global_scope_, identifier, error); |
+} |
+ |
+ResourceRequestBlockedReason WorkerFetchContext::AllowResponse( |
+ Resource::Type type, |
+ const ResourceRequest& resource_request, |
+ const KURL& url, |
+ const ResourceLoaderOptions& options) const { |
+ ResourceRequestBlockedReason blocked_reason = |
+ CanRequestInternal(type, resource_request, url, options, |
+ SecurityViolationReportingPolicy::kReport, |
+ FetchParameters::kUseDefaultOriginRestrictionForType, |
+ RedirectStatus::kFollowedRedirect); |
+ if (blocked_reason != ResourceRequestBlockedReason::kNone) { |
+ probe::didBlockRequest(worker_global_scope_, resource_request, nullptr, |
+ options.initiator_info, blocked_reason); |
+ } |
+ return blocked_reason; |
+} |
+ |
+void WorkerFetchContext::AddResourceTiming(const ResourceTimingInfo& info) { |
+ WorkerGlobalScopePerformance::performance(*worker_global_scope_) |
+ ->AddResourceTiming(info); |
+} |
+ |
+ResourceRequestBlockedReason WorkerFetchContext::CanRequestInternal( |
+ Resource::Type type, |
+ const ResourceRequest& resource_request, |
+ const KURL& url, |
+ const ResourceLoaderOptions& options, |
+ SecurityViolationReportingPolicy reporting_policy, |
+ FetchParameters::OriginRestriction origin_restriction, |
+ ResourceRequest::RedirectStatus redirect_status) const { |
+ bool should_block_request = false; |
+ probe::shouldBlockRequest(worker_global_scope_, resource_request, |
+ &should_block_request); |
+ if (should_block_request) |
+ return ResourceRequestBlockedReason::kInspector; |
+ |
+ SecurityOrigin* security_origin = options.security_origin.Get(); |
+ if (!security_origin) |
+ security_origin = worker_global_scope_->GetSecurityOrigin(); |
+ if (!security_origin->CanDisplay(url)) { |
+ if (origin_restriction == FetchParameters::kRestrictToSameOrigin) { |
+ return ResourceRequestBlockedReason::kOrigin; |
+ } |
+ } |
+ |
+ if (!url.User().IsEmpty() || !url.Pass().IsEmpty()) { |
+ // See https://crbug.com/504300 |
+ if (RuntimeEnabledFeatures::blockCredentialedSubresourcesEnabled()) |
+ return ResourceRequestBlockedReason::kOrigin; |
+ } |
+ |
+ // TODO(horo): Check GetStrictMixedContentChecking() |
+ // TODO(horo): Implement reporting. |
+ if (MixedContentChecker::IsMixedContent(security_origin, url)) |
+ return ResourceRequestBlockedReason::kMixedContent; |
+ |
+ // TODO(horo): Implement subresource filter. |
+ |
+ if (!worker_global_scope_->GetContentSecurityPolicy()->AllowRequest( |
+ resource_request.GetRequestContext(), url, |
+ options.content_security_policy_nonce, options.integrity_metadata, |
+ options.parser_disposition, redirect_status, reporting_policy)) { |
+ return ResourceRequestBlockedReason::CSP; |
+ } |
+ |
+ return ResourceRequestBlockedReason::kNone; |
+} |
+ |
+RefPtr<WebTaskRunner> WorkerFetchContext::TimerTaskRunner() const { |
+ return timer_task_runner_; |
+} |
+ |
+RefPtr<WebTaskRunner> WorkerFetchContext::LoadingTaskRunner() const { |
+ return loading_task_runner_; |
+} |
+ |
+Resource::ResourceCallback* WorkerFetchContext::GetResourceCallback() { |
+ return resource_callback_; |
+} |
+ |
+DEFINE_TRACE(WorkerFetchContext) { |
+ visitor->Trace(worker_global_scope_); |
+ visitor->Trace(resource_fetcher_); |
+ visitor->Trace(resource_callback_); |
+ FetchContext::Trace(visitor); |
+} |
+ |
void ProvideWorkerFetchContextToWorker( |
WorkerClients* clients, |
std::unique_ptr<WebWorkerFetchContext> web_context) { |