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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "core/loader/WorkerFetchContext.h"
6
7 #include "core/loader/MixedContentChecker.h"
8 #include "core/probe/CoreProbes.h"
9 #include "core/timing/WorkerGlobalScopePerformance.h"
10 #include "core/workers/WorkerGlobalScope.h"
11 #include "platform/RuntimeEnabledFeatures.h"
12 #include "platform/WebTaskRunner.h"
13 #include "platform/exported/WrappedResourceRequest.h"
14 #include "platform/loader/fetch/ResourceFetcher.h"
15 #include "platform/weborigin/SecurityPolicy.h"
16 #include "public/platform/Platform.h"
17 #include "public/platform/WebMixedContent.h"
18 #include "public/platform/WebMixedContentContextType.h"
19 #include "public/platform/WebScheduler.h"
20 #include "public/platform/WebThread.h"
21 #include "public/platform/WebWorkerFetchContext.h"
22
23 namespace blink {
24
25 namespace {
26
27 class WorkerContextSupplement final
28 : public GarbageCollectedFinalized<WorkerContextSupplement>,
29 public Supplement<ExecutionContext> {
30 USING_GARBAGE_COLLECTED_MIXIN(WorkerContextSupplement);
31
32 public:
33 static WorkerContextSupplement* from(ExecutionContext& executionContext) {
34 if (!executionContext.isWorkerGlobalScope())
35 return nullptr;
36 WorkerContextSupplement* supplement = static_cast<WorkerContextSupplement*>(
37 Supplement<ExecutionContext>::from(executionContext, supplementName()));
38 if (supplement)
39 return supplement;
40 WorkerClients* clients = toWorkerGlobalScope(executionContext).clients();
41 if (!clients)
42 return nullptr;
43 WorkerFetchContextInfo* contextInfo =
44 WorkerFetchContextInfo::from(*clients);
45 if (!contextInfo)
46 return nullptr;
47 WorkerFetchContext* workerFetchContext = WorkerFetchContext::create(
48 toWorkerGlobalScope(executionContext), contextInfo);
49 supplement = new WorkerContextSupplement(workerFetchContext);
50 Supplement<ExecutionContext>::provideTo(executionContext, supplementName(),
51 supplement);
52 return supplement;
53 }
54 WorkerFetchContext* context() const { return m_workerFetchContext; }
55
56 DEFINE_INLINE_VIRTUAL_TRACE() {
57 visitor->trace(m_workerFetchContext);
58 Supplement<ExecutionContext>::trace(visitor);
59 }
60
61 private:
62 explicit WorkerContextSupplement(WorkerFetchContext* workerFetchContext)
63 : m_workerFetchContext(workerFetchContext) {}
64 static const char* supplementName() { return "WorkerContextSupplement"; }
65 Member<WorkerFetchContext> m_workerFetchContext;
66 };
67 }
68
69 class WorkerFetchContext::WorkerResourceCallback final
70 : public GarbageCollectedFinalized<WorkerResourceCallback>,
71 public Resource::ResourceCallback {
72 public:
73 WorkerResourceCallback(WebTaskRunner* loadingTaskRunner)
74 : m_loadingTaskRunner(loadingTaskRunner) {}
75 ~WorkerResourceCallback() {}
76 void schedule(Resource*) override;
77 void cancel(Resource*) override;
78 bool isScheduled(Resource*) const override;
79 DECLARE_TRACE();
80
81 private:
82 void runTask();
83
84 RefPtr<WebTaskRunner> m_loadingTaskRunner;
85 TaskHandle m_taskHandle;
86 HeapHashSet<Member<Resource>> m_resourcesWithPendingClients;
87 };
88
89 DEFINE_TRACE(WorkerFetchContext::WorkerResourceCallback) {
90 visitor->trace(m_resourcesWithPendingClients);
91 }
92
93 void WorkerFetchContext::WorkerResourceCallback::schedule(Resource* resource) {
94 if (!m_taskHandle.isActive()) {
95 m_taskHandle = m_loadingTaskRunner->postCancellableTask(
96 BLINK_FROM_HERE,
97 WTF::bind(&WorkerResourceCallback::runTask, wrapWeakPersistent(this)));
98 }
99 m_resourcesWithPendingClients.insert(resource);
100 }
101
102 void WorkerFetchContext::WorkerResourceCallback::cancel(Resource* resource) {
103 m_resourcesWithPendingClients.erase(resource);
104 if (m_taskHandle.isActive() && m_resourcesWithPendingClients.isEmpty())
105 m_taskHandle.cancel();
106 }
107
108 bool WorkerFetchContext::WorkerResourceCallback::isScheduled(
109 Resource* resource) const {
110 return m_resourcesWithPendingClients.contains(resource);
111 }
112
113 void WorkerFetchContext::WorkerResourceCallback::runTask() {
114 HeapVector<Member<Resource>> resources;
115 for (const Member<Resource>& resource : m_resourcesWithPendingClients)
116 resources.push_back(resource.get());
117 m_resourcesWithPendingClients.clear();
118
119 for (const auto& resource : resources)
120 resource->finishPendingClients();
121 }
122
123 WorkerFetchContext* WorkerFetchContext::create(
124 WorkerGlobalScope& workerGlobalScope,
125 WorkerFetchContextInfo* contextInfo) {
126 return new WorkerFetchContext(
127 workerGlobalScope, contextInfo->CreateContext(),
128 contextInfo->isDataSaverEnabled(),
129 contextInfo->isStrictMixedContentCheckingEnabled());
130 }
131
132 WorkerFetchContext::~WorkerFetchContext() {}
133
134 WorkerFetchContext* WorkerFetchContext::from(
135 ExecutionContext& executionContext) {
136 WorkerContextSupplement* supplement =
137 WorkerContextSupplement::from(executionContext);
138 if (!supplement)
139 return nullptr;
140 return supplement->context();
141 }
142
143 WorkerFetchContext::WorkerFetchContext(
144 WorkerGlobalScope& workerGlobalScope,
145 std::unique_ptr<WebWorkerFetchContext> context,
146 bool dataSaverEnabled,
147 bool strictMixedContentCheckingEnabled)
148 : m_workerGlobalScope(workerGlobalScope),
149 m_context(std::move(context)),
150 m_loadingTaskRunner(Platform::current()
151 ->currentThread()
152 ->scheduler()
153 ->loadingTaskRunner()),
154 m_timerTaskRunner(
155 Platform::current()->currentThread()->scheduler()->timerTaskRunner()),
156 m_dataSaverEnabled(dataSaverEnabled),
157 m_strictMixedContentCheckingEnabled(strictMixedContentCheckingEnabled),
158 m_resourceCallback(
159 new WorkerResourceCallback(m_loadingTaskRunner.get())) {}
160
161 bool WorkerFetchContext::isControlledByServiceWorker() const {
162 return m_context->IsControlledByServiceWorker();
163 }
164
165 int64_t WorkerFetchContext::serviceWorkerID() const {
166 // TODO(horo): serviceWorkerID() is used only for memory cache which is
167 // disabled in worker thread. So we should remove this method.
168 return m_context->serviceWorkerID();
169 }
170
171 ResourceRequestBlockedReason WorkerFetchContext::canRequest(
172 Resource::Type type,
173 const ResourceRequest& resourceRequest,
174 const KURL& url,
175 const ResourceLoaderOptions& options,
176 SecurityViolationReportingPolicy reportingPolicy,
177 FetchRequest::OriginRestriction originRestriction) const {
178 ResourceRequestBlockedReason blockedReason =
179 canRequestInternal(type, resourceRequest, url, options, reportingPolicy,
180 originRestriction, resourceRequest.redirectStatus());
181 if (blockedReason != ResourceRequestBlockedReason::None) {
182 probe::didBlockRequest(m_workerGlobalScope, resourceRequest, nullptr,
183 options.initiatorInfo, blockedReason);
184 }
185 return blockedReason;
186 }
187
188 void WorkerFetchContext::addAdditionalRequestHeaders(ResourceRequest& request,
189 FetchResourceType type) {
190 bool isMainResource = type == FetchMainResource;
191 if (!isMainResource) {
192 if (!request.didSetHTTPReferrer()) {
193 request.setHTTPReferrer(SecurityPolicy::generateReferrer(
194 m_workerGlobalScope->getReferrerPolicy(), request.url(),
195 m_workerGlobalScope->outgoingReferrer()));
196 request.addHTTPOriginIfNeeded(m_workerGlobalScope->getSecurityOrigin());
197 } else {
198 DCHECK_EQ(SecurityPolicy::generateReferrer(request.getReferrerPolicy(),
199 request.url(),
200 request.httpReferrer())
201 .referrer,
202 request.httpReferrer());
203 request.addHTTPOriginIfNeeded(request.httpReferrer());
204 }
205 }
206 }
207
208 void WorkerFetchContext::prepareRequest(ResourceRequest& request,
209 RedirectType) {
210 String userAgent = m_workerGlobalScope->userAgent();
211 probe::applyUserAgentOverride(m_workerGlobalScope, &userAgent);
212 DCHECK(!userAgent.isNull());
213 request.setHTTPUserAgent(AtomicString(userAgent));
214
215 if (m_dataSaverEnabled)
216 request.setHTTPHeaderField("Save-Data", "on");
217
218 request.setIsMojoIPCForced(true);
219 if (request.requestorOrigin()->isUnique() &&
220 !m_workerGlobalScope->getSecurityOrigin()->isUnique()) {
221 request.setRequestorOrigin(m_workerGlobalScope->getSecurityOrigin());
222 }
223 WrappedResourceRequest webreq(request);
224 m_context->willSendRequest(webreq);
225 }
226
227 void WorkerFetchContext::dispatchWillSendRequest(
228 unsigned long identifier,
229 ResourceRequest& request,
230 const ResourceResponse& redirectResponse,
231 const FetchInitiatorInfo& initiatorInfo) {
232 probe::willSendRequest(m_workerGlobalScope, identifier, nullptr, request,
233 redirectResponse, initiatorInfo);
234 }
235
236 void WorkerFetchContext::dispatchDidReceiveResponse(
237 unsigned long identifier,
238 const ResourceResponse& response,
239 WebURLRequest::FrameType frameType,
240 WebURLRequest::RequestContext requestContext,
241 Resource* resource,
242 ResourceResponseType) {
243 if (response.hasMajorCertificateErrors()) {
244 WebMixedContentContextType contextType =
245 WebMixedContent::contextTypeFromRequestContext(
246 requestContext, false /* strictMixedContentCheckingForPlugin */);
247 if (contextType == WebMixedContentContextType::Blockable) {
248 m_context->didRunContentWithCertificateErrors(response.url());
249 } else {
250 m_context->didDisplayContentWithCertificateErrors(response.url());
251 }
252 }
253 probe::didReceiveResourceResponse(m_workerGlobalScope, identifier, nullptr,
254 response, resource);
255 }
256
257 void WorkerFetchContext::dispatchDidReceiveData(unsigned long identifier,
258 const char* data,
259 int dataLength) {
260 probe::didReceiveData(m_workerGlobalScope, identifier, nullptr, data,
261 dataLength);
262 }
263
264 void WorkerFetchContext::dispatchDidReceiveEncodedData(unsigned long identifier,
265 int encodedDataLength) {
266 probe::didReceiveEncodedDataLength(m_workerGlobalScope, identifier,
267 encodedDataLength);
268 }
269
270 void WorkerFetchContext::dispatchDidFinishLoading(unsigned long identifier,
271 double finishTime,
272 int64_t encodedDataLength,
273 int64_t decodedBodyLength) {
274 probe::didFinishLoading(m_workerGlobalScope, identifier, nullptr, finishTime,
275 encodedDataLength, decodedBodyLength);
276 }
277
278 void WorkerFetchContext::dispatchDidFail(unsigned long identifier,
279 const ResourceError& error,
280 int64_t encodedDataLength,
281 bool isInternalRequest) {
282 probe::didFailLoading(m_workerGlobalScope, identifier, error);
283 }
284
285 ResourceRequestBlockedReason WorkerFetchContext::allowResponse(
286 Resource::Type type,
287 const ResourceRequest& resourceRequest,
288 const KURL& url,
289 const ResourceLoaderOptions& options) const {
290 ResourceRequestBlockedReason blockedReason =
291 canRequestInternal(type, resourceRequest, url, options,
292 SecurityViolationReportingPolicy::Report,
293 FetchRequest::UseDefaultOriginRestrictionForType,
294 RedirectStatus::FollowedRedirect);
295 if (blockedReason != ResourceRequestBlockedReason::None) {
296 probe::didBlockRequest(m_workerGlobalScope, resourceRequest, nullptr,
297 options.initiatorInfo, blockedReason);
298 }
299 return blockedReason;
300 }
301
302 void WorkerFetchContext::addResourceTiming(const ResourceTimingInfo& info) {
303 WorkerGlobalScopePerformance::performance(*m_workerGlobalScope)
304 ->addResourceTiming(info);
305 }
306
307 ResourceRequestBlockedReason WorkerFetchContext::canRequestInternal(
308 Resource::Type type,
309 const ResourceRequest& resourceRequest,
310 const KURL& url,
311 const ResourceLoaderOptions& options,
312 SecurityViolationReportingPolicy reportingPolicy,
313 FetchRequest::OriginRestriction originRestriction,
314 ResourceRequest::RedirectStatus redirectStatus) const {
315 bool shouldBlockRequest = false;
316 probe::shouldBlockRequest(m_workerGlobalScope, resourceRequest,
317 &shouldBlockRequest);
318 if (shouldBlockRequest)
319 return ResourceRequestBlockedReason::Inspector;
320
321 SecurityOrigin* securityOrigin = options.securityOrigin.get();
322 if (!securityOrigin)
323 securityOrigin = m_workerGlobalScope->getSecurityOrigin();
324 if (!securityOrigin->canDisplay(url)) {
325 if (originRestriction == FetchRequest::RestrictToSameOrigin) {
326 return ResourceRequestBlockedReason::Origin;
327 }
328 }
329
330 if (!url.user().isEmpty() || !url.pass().isEmpty()) {
331 // See https://crbug.com/504300
332 if (RuntimeEnabledFeatures::blockCredentialedSubresourcesEnabled())
333 return ResourceRequestBlockedReason::Origin;
334 }
335
336 // TODO(horo): Check m_strictMixedContentCheckingEnabled
337 // TODO(horo): Implement reporting.
338 if (MixedContentChecker::isMixedContent(securityOrigin, url))
339 return ResourceRequestBlockedReason::MixedContent;
340
341 // TODO(horo): Implement subresource filter.
342
343 if (!m_workerGlobalScope->contentSecurityPolicy()->allowRequest(
344 resourceRequest.requestContext(), url,
345 options.contentSecurityPolicyNonce, options.integrityMetadata,
346 options.parserDisposition, redirectStatus, reportingPolicy)) {
347 return ResourceRequestBlockedReason::CSP;
348 }
349
350 return ResourceRequestBlockedReason::None;
351 }
352
353 WebURLLoader* WorkerFetchContext::createURLLoader() {
354 return m_context->createURLLoader();
355 }
356
357 RefPtr<WebTaskRunner> WorkerFetchContext::timerTaskRunner() const {
358 return m_timerTaskRunner;
359 }
360
361 RefPtr<WebTaskRunner> WorkerFetchContext::loadingTaskRunner() const {
362 return m_loadingTaskRunner;
363 }
364
365 Resource::ResourceCallback* WorkerFetchContext::resourceCallback() {
366 return m_resourceCallback;
367 }
368
369 ResourceFetcher* WorkerFetchContext::getResourceFetcher() {
370 if (m_resourceFetcher)
371 return m_resourceFetcher;
372 m_resourceFetcher = ResourceFetcher::create(this);
373 return m_resourceFetcher;
374 }
375
376 DEFINE_TRACE(WorkerFetchContext) {
377 visitor->trace(m_workerGlobalScope);
378 visitor->trace(m_resourceFetcher);
379 visitor->trace(m_resourceCallback);
380 FetchContext::trace(visitor);
381 }
382
383 // static
384 WorkerFetchContextInfo* WorkerFetchContextInfo::create(
385 std::unique_ptr<WebWorkerFetchContextInfo> info) {
386 return new WorkerFetchContextInfo(std::move(info));
387 }
388
389 // static
390 WorkerFetchContextInfo* WorkerFetchContextInfo::from(WorkerClients& clients) {
391 return static_cast<WorkerFetchContextInfo*>(
392 Supplement<WorkerClients>::from(clients, supplementName()));
393 }
394
395 WorkerFetchContextInfo::WorkerFetchContextInfo(
396 std::unique_ptr<WebWorkerFetchContextInfo> info)
397 : m_info(std::move(info)) {}
398
399 WorkerFetchContextInfo::~WorkerFetchContextInfo() {}
400
401 const char* WorkerFetchContextInfo::supplementName() {
402 return "WorkerFetchContextInfo";
403 }
404
405 std::unique_ptr<WebWorkerFetchContext> WorkerFetchContextInfo::CreateContext() {
406 DCHECK(m_info);
407 DCHECK(!isMainThread());
408 std::unique_ptr<WebWorkerFetchContext> webContext =
409 m_info->CreateContext(Platform::current()
410 ->currentThread()
411 ->scheduler()
412 ->loadingTaskRunner()
413 ->toSingleThreadTaskRunner());
414 m_info.reset();
415 return webContext;
416 }
417
418 void provideWorkerFetchContextInfoToWorker(
419 WorkerClients* clients,
420 std::unique_ptr<WebWorkerFetchContextInfo> info) {
421 DCHECK(clients);
422 WorkerFetchContextInfo::provideTo(
423 *clients, WorkerFetchContextInfo::supplementName(),
424 WorkerFetchContextInfo::create(std::move(info)));
425 }
426
427 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698