| 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) {
|
|
|