| 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
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..49edee064960b9da9c44c63367d293802ef418f5
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp
|
| @@ -0,0 +1,427 @@
|
| +// 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 "core/loader/WorkerFetchContext.h"
|
| +
|
| +#include "core/loader/MixedContentChecker.h"
|
| +#include "core/probe/CoreProbes.h"
|
| +#include "core/timing/WorkerGlobalScopePerformance.h"
|
| +#include "core/workers/WorkerGlobalScope.h"
|
| +#include "platform/RuntimeEnabledFeatures.h"
|
| +#include "platform/WebTaskRunner.h"
|
| +#include "platform/exported/WrappedResourceRequest.h"
|
| +#include "platform/loader/fetch/ResourceFetcher.h"
|
| +#include "platform/weborigin/SecurityPolicy.h"
|
| +#include "public/platform/Platform.h"
|
| +#include "public/platform/WebMixedContent.h"
|
| +#include "public/platform/WebMixedContentContextType.h"
|
| +#include "public/platform/WebScheduler.h"
|
| +#include "public/platform/WebThread.h"
|
| +#include "public/platform/WebWorkerFetchContext.h"
|
| +
|
| +namespace blink {
|
| +
|
| +namespace {
|
| +
|
| +class WorkerContextSupplement final
|
| + : public GarbageCollectedFinalized<WorkerContextSupplement>,
|
| + public Supplement<ExecutionContext> {
|
| + USING_GARBAGE_COLLECTED_MIXIN(WorkerContextSupplement);
|
| +
|
| + public:
|
| + static WorkerContextSupplement* from(ExecutionContext& executionContext) {
|
| + if (!executionContext.isWorkerGlobalScope())
|
| + return nullptr;
|
| + WorkerContextSupplement* supplement = static_cast<WorkerContextSupplement*>(
|
| + Supplement<ExecutionContext>::from(executionContext, supplementName()));
|
| + if (supplement)
|
| + return supplement;
|
| + WorkerClients* clients = toWorkerGlobalScope(executionContext).clients();
|
| + if (!clients)
|
| + return nullptr;
|
| + WorkerFetchContextInfo* contextInfo =
|
| + WorkerFetchContextInfo::from(*clients);
|
| + if (!contextInfo)
|
| + return nullptr;
|
| + WorkerFetchContext* workerFetchContext = WorkerFetchContext::create(
|
| + toWorkerGlobalScope(executionContext), contextInfo);
|
| + supplement = new WorkerContextSupplement(workerFetchContext);
|
| + Supplement<ExecutionContext>::provideTo(executionContext, supplementName(),
|
| + supplement);
|
| + return supplement;
|
| + }
|
| + WorkerFetchContext* context() const { return m_workerFetchContext; }
|
| +
|
| + DEFINE_INLINE_VIRTUAL_TRACE() {
|
| + visitor->trace(m_workerFetchContext);
|
| + Supplement<ExecutionContext>::trace(visitor);
|
| + }
|
| +
|
| + private:
|
| + explicit WorkerContextSupplement(WorkerFetchContext* workerFetchContext)
|
| + : m_workerFetchContext(workerFetchContext) {}
|
| + static const char* supplementName() { return "WorkerContextSupplement"; }
|
| + Member<WorkerFetchContext> m_workerFetchContext;
|
| +};
|
| +}
|
| +
|
| +class WorkerFetchContext::WorkerResourceCallback final
|
| + : public GarbageCollectedFinalized<WorkerResourceCallback>,
|
| + public Resource::ResourceCallback {
|
| + public:
|
| + WorkerResourceCallback(WebTaskRunner* loadingTaskRunner)
|
| + : m_loadingTaskRunner(loadingTaskRunner) {}
|
| + ~WorkerResourceCallback() {}
|
| + void schedule(Resource*) override;
|
| + void cancel(Resource*) override;
|
| + bool isScheduled(Resource*) const override;
|
| + DECLARE_TRACE();
|
| +
|
| + private:
|
| + void runTask();
|
| +
|
| + RefPtr<WebTaskRunner> m_loadingTaskRunner;
|
| + TaskHandle m_taskHandle;
|
| + HeapHashSet<Member<Resource>> m_resourcesWithPendingClients;
|
| +};
|
| +
|
| +DEFINE_TRACE(WorkerFetchContext::WorkerResourceCallback) {
|
| + visitor->trace(m_resourcesWithPendingClients);
|
| +}
|
| +
|
| +void WorkerFetchContext::WorkerResourceCallback::schedule(Resource* resource) {
|
| + if (!m_taskHandle.isActive()) {
|
| + m_taskHandle = m_loadingTaskRunner->postCancellableTask(
|
| + BLINK_FROM_HERE,
|
| + WTF::bind(&WorkerResourceCallback::runTask, wrapWeakPersistent(this)));
|
| + }
|
| + m_resourcesWithPendingClients.insert(resource);
|
| +}
|
| +
|
| +void WorkerFetchContext::WorkerResourceCallback::cancel(Resource* resource) {
|
| + m_resourcesWithPendingClients.erase(resource);
|
| + if (m_taskHandle.isActive() && m_resourcesWithPendingClients.isEmpty())
|
| + m_taskHandle.cancel();
|
| +}
|
| +
|
| +bool WorkerFetchContext::WorkerResourceCallback::isScheduled(
|
| + Resource* resource) const {
|
| + return m_resourcesWithPendingClients.contains(resource);
|
| +}
|
| +
|
| +void WorkerFetchContext::WorkerResourceCallback::runTask() {
|
| + HeapVector<Member<Resource>> resources;
|
| + for (const Member<Resource>& resource : m_resourcesWithPendingClients)
|
| + resources.push_back(resource.get());
|
| + m_resourcesWithPendingClients.clear();
|
| +
|
| + for (const auto& resource : resources)
|
| + resource->finishPendingClients();
|
| +}
|
| +
|
| +WorkerFetchContext* WorkerFetchContext::create(
|
| + WorkerGlobalScope& workerGlobalScope,
|
| + WorkerFetchContextInfo* contextInfo) {
|
| + return new WorkerFetchContext(
|
| + workerGlobalScope, contextInfo->CreateContext(),
|
| + contextInfo->isDataSaverEnabled(),
|
| + contextInfo->isStrictMixedContentCheckingEnabled());
|
| +}
|
| +
|
| +WorkerFetchContext::~WorkerFetchContext() {}
|
| +
|
| +WorkerFetchContext* WorkerFetchContext::from(
|
| + ExecutionContext& executionContext) {
|
| + WorkerContextSupplement* supplement =
|
| + WorkerContextSupplement::from(executionContext);
|
| + if (!supplement)
|
| + return nullptr;
|
| + return supplement->context();
|
| +}
|
| +
|
| +WorkerFetchContext::WorkerFetchContext(
|
| + WorkerGlobalScope& workerGlobalScope,
|
| + std::unique_ptr<WebWorkerFetchContext> context,
|
| + bool dataSaverEnabled,
|
| + bool strictMixedContentCheckingEnabled)
|
| + : m_workerGlobalScope(workerGlobalScope),
|
| + m_context(std::move(context)),
|
| + m_loadingTaskRunner(Platform::current()
|
| + ->currentThread()
|
| + ->scheduler()
|
| + ->loadingTaskRunner()),
|
| + m_timerTaskRunner(
|
| + Platform::current()->currentThread()->scheduler()->timerTaskRunner()),
|
| + m_dataSaverEnabled(dataSaverEnabled),
|
| + m_strictMixedContentCheckingEnabled(strictMixedContentCheckingEnabled),
|
| + m_resourceCallback(
|
| + new WorkerResourceCallback(m_loadingTaskRunner.get())) {}
|
| +
|
| +bool WorkerFetchContext::isControlledByServiceWorker() const {
|
| + return m_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 m_context->serviceWorkerID();
|
| +}
|
| +
|
| +ResourceRequestBlockedReason WorkerFetchContext::canRequest(
|
| + Resource::Type type,
|
| + const ResourceRequest& resourceRequest,
|
| + const KURL& url,
|
| + const ResourceLoaderOptions& options,
|
| + SecurityViolationReportingPolicy reportingPolicy,
|
| + FetchRequest::OriginRestriction originRestriction) const {
|
| + ResourceRequestBlockedReason blockedReason =
|
| + canRequestInternal(type, resourceRequest, url, options, reportingPolicy,
|
| + originRestriction, resourceRequest.redirectStatus());
|
| + if (blockedReason != ResourceRequestBlockedReason::None) {
|
| + probe::didBlockRequest(m_workerGlobalScope, resourceRequest, nullptr,
|
| + options.initiatorInfo, blockedReason);
|
| + }
|
| + return blockedReason;
|
| +}
|
| +
|
| +void WorkerFetchContext::addAdditionalRequestHeaders(ResourceRequest& request,
|
| + FetchResourceType type) {
|
| + bool isMainResource = type == FetchMainResource;
|
| + if (!isMainResource) {
|
| + if (!request.didSetHTTPReferrer()) {
|
| + request.setHTTPReferrer(SecurityPolicy::generateReferrer(
|
| + m_workerGlobalScope->getReferrerPolicy(), request.url(),
|
| + m_workerGlobalScope->outgoingReferrer()));
|
| + request.addHTTPOriginIfNeeded(m_workerGlobalScope->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 userAgent = m_workerGlobalScope->userAgent();
|
| + probe::applyUserAgentOverride(m_workerGlobalScope, &userAgent);
|
| + DCHECK(!userAgent.isNull());
|
| + request.setHTTPUserAgent(AtomicString(userAgent));
|
| +
|
| + if (m_dataSaverEnabled)
|
| + request.setHTTPHeaderField("Save-Data", "on");
|
| +
|
| + request.setIsMojoIPCForced(true);
|
| + if (request.requestorOrigin()->isUnique() &&
|
| + !m_workerGlobalScope->getSecurityOrigin()->isUnique()) {
|
| + request.setRequestorOrigin(m_workerGlobalScope->getSecurityOrigin());
|
| + }
|
| + WrappedResourceRequest webreq(request);
|
| + m_context->willSendRequest(webreq);
|
| +}
|
| +
|
| +void WorkerFetchContext::dispatchWillSendRequest(
|
| + unsigned long identifier,
|
| + ResourceRequest& request,
|
| + const ResourceResponse& redirectResponse,
|
| + const FetchInitiatorInfo& initiatorInfo) {
|
| + probe::willSendRequest(m_workerGlobalScope, identifier, nullptr, request,
|
| + redirectResponse, initiatorInfo);
|
| +}
|
| +
|
| +void WorkerFetchContext::dispatchDidReceiveResponse(
|
| + unsigned long identifier,
|
| + const ResourceResponse& response,
|
| + WebURLRequest::FrameType frameType,
|
| + WebURLRequest::RequestContext requestContext,
|
| + Resource* resource,
|
| + ResourceResponseType) {
|
| + if (response.hasMajorCertificateErrors()) {
|
| + WebMixedContentContextType contextType =
|
| + WebMixedContent::contextTypeFromRequestContext(
|
| + requestContext, false /* strictMixedContentCheckingForPlugin */);
|
| + if (contextType == WebMixedContentContextType::Blockable) {
|
| + m_context->didRunContentWithCertificateErrors(response.url());
|
| + } else {
|
| + m_context->didDisplayContentWithCertificateErrors(response.url());
|
| + }
|
| + }
|
| + probe::didReceiveResourceResponse(m_workerGlobalScope, identifier, nullptr,
|
| + response, resource);
|
| +}
|
| +
|
| +void WorkerFetchContext::dispatchDidReceiveData(unsigned long identifier,
|
| + const char* data,
|
| + int dataLength) {
|
| + probe::didReceiveData(m_workerGlobalScope, identifier, nullptr, data,
|
| + dataLength);
|
| +}
|
| +
|
| +void WorkerFetchContext::dispatchDidReceiveEncodedData(unsigned long identifier,
|
| + int encodedDataLength) {
|
| + probe::didReceiveEncodedDataLength(m_workerGlobalScope, identifier,
|
| + encodedDataLength);
|
| +}
|
| +
|
| +void WorkerFetchContext::dispatchDidFinishLoading(unsigned long identifier,
|
| + double finishTime,
|
| + int64_t encodedDataLength,
|
| + int64_t decodedBodyLength) {
|
| + probe::didFinishLoading(m_workerGlobalScope, identifier, nullptr, finishTime,
|
| + encodedDataLength, decodedBodyLength);
|
| +}
|
| +
|
| +void WorkerFetchContext::dispatchDidFail(unsigned long identifier,
|
| + const ResourceError& error,
|
| + int64_t encodedDataLength,
|
| + bool isInternalRequest) {
|
| + probe::didFailLoading(m_workerGlobalScope, identifier, error);
|
| +}
|
| +
|
| +ResourceRequestBlockedReason WorkerFetchContext::allowResponse(
|
| + Resource::Type type,
|
| + const ResourceRequest& resourceRequest,
|
| + const KURL& url,
|
| + const ResourceLoaderOptions& options) const {
|
| + ResourceRequestBlockedReason blockedReason =
|
| + canRequestInternal(type, resourceRequest, url, options,
|
| + SecurityViolationReportingPolicy::Report,
|
| + FetchRequest::UseDefaultOriginRestrictionForType,
|
| + RedirectStatus::FollowedRedirect);
|
| + if (blockedReason != ResourceRequestBlockedReason::None) {
|
| + probe::didBlockRequest(m_workerGlobalScope, resourceRequest, nullptr,
|
| + options.initiatorInfo, blockedReason);
|
| + }
|
| + return blockedReason;
|
| +}
|
| +
|
| +void WorkerFetchContext::addResourceTiming(const ResourceTimingInfo& info) {
|
| + WorkerGlobalScopePerformance::performance(*m_workerGlobalScope)
|
| + ->addResourceTiming(info);
|
| +}
|
| +
|
| +ResourceRequestBlockedReason WorkerFetchContext::canRequestInternal(
|
| + Resource::Type type,
|
| + const ResourceRequest& resourceRequest,
|
| + const KURL& url,
|
| + const ResourceLoaderOptions& options,
|
| + SecurityViolationReportingPolicy reportingPolicy,
|
| + FetchRequest::OriginRestriction originRestriction,
|
| + ResourceRequest::RedirectStatus redirectStatus) const {
|
| + bool shouldBlockRequest = false;
|
| + probe::shouldBlockRequest(m_workerGlobalScope, resourceRequest,
|
| + &shouldBlockRequest);
|
| + if (shouldBlockRequest)
|
| + return ResourceRequestBlockedReason::Inspector;
|
| +
|
| + SecurityOrigin* securityOrigin = options.securityOrigin.get();
|
| + if (!securityOrigin)
|
| + securityOrigin = m_workerGlobalScope->getSecurityOrigin();
|
| + if (!securityOrigin->canDisplay(url)) {
|
| + if (originRestriction == FetchRequest::RestrictToSameOrigin) {
|
| + return ResourceRequestBlockedReason::Origin;
|
| + }
|
| + }
|
| +
|
| + if (!url.user().isEmpty() || !url.pass().isEmpty()) {
|
| + // See https://crbug.com/504300
|
| + if (RuntimeEnabledFeatures::blockCredentialedSubresourcesEnabled())
|
| + return ResourceRequestBlockedReason::Origin;
|
| + }
|
| +
|
| + // TODO(horo): Check m_strictMixedContentCheckingEnabled
|
| + // TODO(horo): Implement reporting.
|
| + if (MixedContentChecker::isMixedContent(securityOrigin, url))
|
| + return ResourceRequestBlockedReason::MixedContent;
|
| +
|
| + // TODO(horo): Implement subresource filter.
|
| +
|
| + if (!m_workerGlobalScope->contentSecurityPolicy()->allowRequest(
|
| + resourceRequest.requestContext(), url,
|
| + options.contentSecurityPolicyNonce, options.integrityMetadata,
|
| + options.parserDisposition, redirectStatus, reportingPolicy)) {
|
| + return ResourceRequestBlockedReason::CSP;
|
| + }
|
| +
|
| + return ResourceRequestBlockedReason::None;
|
| +}
|
| +
|
| +WebURLLoader* WorkerFetchContext::createURLLoader() {
|
| + return m_context->createURLLoader();
|
| +}
|
| +
|
| +RefPtr<WebTaskRunner> WorkerFetchContext::timerTaskRunner() const {
|
| + return m_timerTaskRunner;
|
| +}
|
| +
|
| +RefPtr<WebTaskRunner> WorkerFetchContext::loadingTaskRunner() const {
|
| + return m_loadingTaskRunner;
|
| +}
|
| +
|
| +Resource::ResourceCallback* WorkerFetchContext::resourceCallback() {
|
| + return m_resourceCallback;
|
| +}
|
| +
|
| +ResourceFetcher* WorkerFetchContext::getResourceFetcher() {
|
| + if (m_resourceFetcher)
|
| + return m_resourceFetcher;
|
| + m_resourceFetcher = ResourceFetcher::create(this);
|
| + return m_resourceFetcher;
|
| +}
|
| +
|
| +DEFINE_TRACE(WorkerFetchContext) {
|
| + visitor->trace(m_workerGlobalScope);
|
| + visitor->trace(m_resourceFetcher);
|
| + visitor->trace(m_resourceCallback);
|
| + FetchContext::trace(visitor);
|
| +}
|
| +
|
| +// static
|
| +WorkerFetchContextInfo* WorkerFetchContextInfo::create(
|
| + std::unique_ptr<WebWorkerFetchContextInfo> info) {
|
| + return new WorkerFetchContextInfo(std::move(info));
|
| +}
|
| +
|
| +// static
|
| +WorkerFetchContextInfo* WorkerFetchContextInfo::from(WorkerClients& clients) {
|
| + return static_cast<WorkerFetchContextInfo*>(
|
| + Supplement<WorkerClients>::from(clients, supplementName()));
|
| +}
|
| +
|
| +WorkerFetchContextInfo::WorkerFetchContextInfo(
|
| + std::unique_ptr<WebWorkerFetchContextInfo> info)
|
| + : m_info(std::move(info)) {}
|
| +
|
| +WorkerFetchContextInfo::~WorkerFetchContextInfo() {}
|
| +
|
| +const char* WorkerFetchContextInfo::supplementName() {
|
| + return "WorkerFetchContextInfo";
|
| +}
|
| +
|
| +std::unique_ptr<WebWorkerFetchContext> WorkerFetchContextInfo::CreateContext() {
|
| + DCHECK(m_info);
|
| + DCHECK(!isMainThread());
|
| + std::unique_ptr<WebWorkerFetchContext> webContext =
|
| + m_info->CreateContext(Platform::current()
|
| + ->currentThread()
|
| + ->scheduler()
|
| + ->loadingTaskRunner()
|
| + ->toSingleThreadTaskRunner());
|
| + m_info.reset();
|
| + return webContext;
|
| +}
|
| +
|
| +void provideWorkerFetchContextInfoToWorker(
|
| + WorkerClients* clients,
|
| + std::unique_ptr<WebWorkerFetchContextInfo> info) {
|
| + DCHECK(clients);
|
| + WorkerFetchContextInfo::provideTo(
|
| + *clients, WorkerFetchContextInfo::supplementName(),
|
| + WorkerFetchContextInfo::create(std::move(info)));
|
| +}
|
| +
|
| +} // namespace blink
|
|
|