Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(109)

Unified Diff: third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp

Issue 2701753003: [WIP] off-main-thread loading
Patch Set: small fix Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698