OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/loader/WorkerFetchContext.h" | 5 #include "core/loader/WorkerFetchContext.h" |
6 | 6 |
| 7 #include "core/loader/MixedContentChecker.h" |
| 8 #include "core/probe/CoreProbes.h" |
| 9 #include "core/timing/WorkerGlobalScopePerformance.h" |
7 #include "core/workers/WorkerClients.h" | 10 #include "core/workers/WorkerClients.h" |
8 #include "core/workers/WorkerGlobalScope.h" | 11 #include "core/workers/WorkerGlobalScope.h" |
| 12 #include "platform/RuntimeEnabledFeatures.h" |
9 #include "platform/Supplementable.h" | 13 #include "platform/Supplementable.h" |
10 #include "platform/WebTaskRunner.h" | 14 #include "platform/WebTaskRunner.h" |
11 #include "platform/exported/WrappedResourceRequest.h" | 15 #include "platform/exported/WrappedResourceRequest.h" |
| 16 #include "platform/loader/fetch/ResourceFetcher.h" |
12 #include "platform/scheduler/child/web_scheduler.h" | 17 #include "platform/scheduler/child/web_scheduler.h" |
| 18 #include "platform/weborigin/SecurityPolicy.h" |
13 #include "public/platform/Platform.h" | 19 #include "public/platform/Platform.h" |
| 20 #include "public/platform/WebMixedContent.h" |
| 21 #include "public/platform/WebMixedContentContextType.h" |
14 #include "public/platform/WebThread.h" | 22 #include "public/platform/WebThread.h" |
15 #include "public/platform/WebWorkerFetchContext.h" | 23 #include "public/platform/WebWorkerFetchContext.h" |
16 | 24 |
17 namespace blink { | 25 namespace blink { |
18 | 26 |
19 namespace { | 27 namespace { |
20 | 28 |
21 // WorkerFetchContextHolder is used to pass the WebWorkerFetchContext from the | 29 // WorkerFetchContextHolder is used to pass the WebWorkerFetchContext from the |
22 // main thread to the worker thread by attaching to the WorkerClients as a | 30 // main thread to the worker thread by attaching to the WorkerClients as a |
23 // Supplement. | 31 // Supplement. |
(...skipping 19 matching lines...) Expand all Loading... |
43 } | 51 } |
44 | 52 |
45 DEFINE_INLINE_VIRTUAL_TRACE() { Supplement<WorkerClients>::Trace(visitor); } | 53 DEFINE_INLINE_VIRTUAL_TRACE() { Supplement<WorkerClients>::Trace(visitor); } |
46 | 54 |
47 private: | 55 private: |
48 std::unique_ptr<WebWorkerFetchContext> web_context_; | 56 std::unique_ptr<WebWorkerFetchContext> web_context_; |
49 }; | 57 }; |
50 | 58 |
51 } // namespace | 59 } // namespace |
52 | 60 |
| 61 class WorkerFetchContext::WorkerResourceCallback final |
| 62 : public GarbageCollectedFinalized<WorkerResourceCallback>, |
| 63 public Resource::ResourceCallback { |
| 64 public: |
| 65 WorkerResourceCallback(WebTaskRunner* loading_task_runner) |
| 66 : loading_task_runner_(loading_task_runner) {} |
| 67 ~WorkerResourceCallback() {} |
| 68 void Schedule(Resource*) override; |
| 69 void Cancel(Resource*) override; |
| 70 bool IsScheduled(Resource*) const override; |
| 71 DECLARE_TRACE(); |
| 72 |
| 73 private: |
| 74 void RunTask(); |
| 75 |
| 76 RefPtr<WebTaskRunner> loading_task_runner_; |
| 77 TaskHandle task_handle_; |
| 78 HeapHashSet<Member<Resource>> resources_with_pending_clients_; |
| 79 }; |
| 80 |
| 81 DEFINE_TRACE(WorkerFetchContext::WorkerResourceCallback) { |
| 82 visitor->Trace(resources_with_pending_clients_); |
| 83 } |
| 84 |
| 85 void WorkerFetchContext::WorkerResourceCallback::Schedule(Resource* resource) { |
| 86 if (!task_handle_.IsActive()) { |
| 87 task_handle_ = loading_task_runner_->PostCancellableTask( |
| 88 BLINK_FROM_HERE, |
| 89 WTF::Bind(&WorkerResourceCallback::RunTask, WrapWeakPersistent(this))); |
| 90 } |
| 91 resources_with_pending_clients_.insert(resource); |
| 92 } |
| 93 |
| 94 void WorkerFetchContext::WorkerResourceCallback::Cancel(Resource* resource) { |
| 95 resources_with_pending_clients_.erase(resource); |
| 96 if (task_handle_.IsActive() && resources_with_pending_clients_.IsEmpty()) |
| 97 task_handle_.Cancel(); |
| 98 } |
| 99 |
| 100 bool WorkerFetchContext::WorkerResourceCallback::IsScheduled( |
| 101 Resource* resource) const { |
| 102 return resources_with_pending_clients_.Contains(resource); |
| 103 } |
| 104 |
| 105 void WorkerFetchContext::WorkerResourceCallback::RunTask() { |
| 106 HeapVector<Member<Resource>> resources; |
| 107 for (const Member<Resource>& resource : resources_with_pending_clients_) |
| 108 resources.push_back(resource); |
| 109 resources_with_pending_clients_.clear(); |
| 110 |
| 111 for (const auto& resource : resources) |
| 112 resource->FinishPendingClients(); |
| 113 } |
| 114 |
53 WorkerFetchContext::~WorkerFetchContext() {} | 115 WorkerFetchContext::~WorkerFetchContext() {} |
54 | 116 |
55 WorkerFetchContext* WorkerFetchContext::Create( | 117 WorkerFetchContext* WorkerFetchContext::Create( |
56 WorkerGlobalScope& worker_global_scope) { | 118 WorkerGlobalScope& worker_global_scope) { |
57 DCHECK(worker_global_scope.IsContextThread()); | 119 DCHECK(worker_global_scope.IsContextThread()); |
58 WorkerClients* worker_clients = worker_global_scope.Clients(); | 120 WorkerClients* worker_clients = worker_global_scope.Clients(); |
59 DCHECK(worker_clients); | 121 if (!worker_clients) |
| 122 return nullptr; |
60 WorkerFetchContextHolder* holder = | 123 WorkerFetchContextHolder* holder = |
61 static_cast<WorkerFetchContextHolder*>(Supplement<WorkerClients>::From( | 124 static_cast<WorkerFetchContextHolder*>(Supplement<WorkerClients>::From( |
62 *worker_clients, WorkerFetchContextHolder::SupplementName())); | 125 *worker_clients, WorkerFetchContextHolder::SupplementName())); |
63 if (!holder) | 126 if (!holder) |
64 return nullptr; | 127 return nullptr; |
65 std::unique_ptr<WebWorkerFetchContext> web_context = holder->TakeContext(); | 128 std::unique_ptr<WebWorkerFetchContext> web_context = holder->TakeContext(); |
66 DCHECK(web_context); | 129 DCHECK(web_context); |
67 return new WorkerFetchContext(std::move(web_context)); | 130 return new WorkerFetchContext(worker_global_scope, std::move(web_context)); |
68 } | 131 } |
69 | 132 |
70 WorkerFetchContext::WorkerFetchContext( | 133 WorkerFetchContext::WorkerFetchContext( |
| 134 WorkerGlobalScope& worker_global_scope, |
71 std::unique_ptr<WebWorkerFetchContext> web_context) | 135 std::unique_ptr<WebWorkerFetchContext> web_context) |
72 : web_context_(std::move(web_context)) { | 136 : worker_global_scope_(worker_global_scope), |
73 web_context_->InitializeOnWorkerThread(Platform::Current() | 137 web_context_(std::move(web_context)), |
74 ->CurrentThread() | 138 loading_task_runner_(Platform::Current() |
75 ->Scheduler() | 139 ->CurrentThread() |
76 ->LoadingTaskRunner() | 140 ->Scheduler() |
77 ->ToSingleThreadTaskRunner()); | 141 ->LoadingTaskRunner()), |
| 142 timer_task_runner_( |
| 143 Platform::Current()->CurrentThread()->Scheduler()->TimerTaskRunner()), |
| 144 resource_callback_( |
| 145 new WorkerResourceCallback(loading_task_runner_.Get())) { |
| 146 web_context_->InitializeOnWorkerThread( |
| 147 loading_task_runner_->ToSingleThreadTaskRunner()); |
| 148 } |
| 149 |
| 150 ResourceFetcher* WorkerFetchContext::GetResourceFetcher() { |
| 151 if (resource_fetcher_) |
| 152 return resource_fetcher_; |
| 153 resource_fetcher_ = ResourceFetcher::Create(this); |
| 154 return resource_fetcher_; |
78 } | 155 } |
79 | 156 |
80 std::unique_ptr<WebURLLoader> WorkerFetchContext::CreateURLLoader() { | 157 std::unique_ptr<WebURLLoader> WorkerFetchContext::CreateURLLoader() { |
81 return web_context_->CreateURLLoader(); | 158 return web_context_->CreateURLLoader(); |
82 } | 159 } |
83 | 160 |
84 bool WorkerFetchContext::IsControlledByServiceWorker() const { | 161 bool WorkerFetchContext::IsControlledByServiceWorker() const { |
85 return web_context_->IsControlledByServiceWorker(); | 162 return web_context_->IsControlledByServiceWorker(); |
86 } | 163 } |
87 | 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 web_context_->ServiceWorkerID(); |
| 169 } |
| 170 |
| 171 ResourceRequestBlockedReason WorkerFetchContext::CanRequest( |
| 172 Resource::Type type, |
| 173 const ResourceRequest& resource_request, |
| 174 const KURL& url, |
| 175 const ResourceLoaderOptions& options, |
| 176 SecurityViolationReportingPolicy reporting_policy, |
| 177 FetchParameters::OriginRestriction origin_restriction) const { |
| 178 ResourceRequestBlockedReason blocked_reason = CanRequestInternal( |
| 179 type, resource_request, url, options, reporting_policy, |
| 180 origin_restriction, resource_request.GetRedirectStatus()); |
| 181 if (blocked_reason != ResourceRequestBlockedReason::kNone) { |
| 182 probe::didBlockRequest(worker_global_scope_, resource_request, nullptr, |
| 183 options.initiator_info, blocked_reason); |
| 184 } |
| 185 return blocked_reason; |
| 186 } |
| 187 |
| 188 ResourceRequestBlockedReason WorkerFetchContext::CanFollowRedirect( |
| 189 Resource::Type type, |
| 190 const ResourceRequest& resource_request, |
| 191 const KURL& url, |
| 192 const ResourceLoaderOptions& options, |
| 193 SecurityViolationReportingPolicy reporting_policy, |
| 194 FetchParameters::OriginRestriction origin_restriction) const { |
| 195 ResourceRequestBlockedReason blocked_reason = CanRequestInternal( |
| 196 type, resource_request, url, options, reporting_policy, |
| 197 origin_restriction, resource_request.GetRedirectStatus()); |
| 198 if (blocked_reason != ResourceRequestBlockedReason::kNone) { |
| 199 probe::didBlockRequest(worker_global_scope_, resource_request, nullptr, |
| 200 options.initiator_info, blocked_reason); |
| 201 } |
| 202 return blocked_reason; |
| 203 } |
| 204 |
| 205 void WorkerFetchContext::AddAdditionalRequestHeaders(ResourceRequest& request, |
| 206 FetchResourceType type) { |
| 207 bool isMainResource = type == kFetchMainResource; |
| 208 if (!isMainResource) { |
| 209 if (!request.DidSetHTTPReferrer()) { |
| 210 request.SetHTTPReferrer(SecurityPolicy::GenerateReferrer( |
| 211 worker_global_scope_->GetReferrerPolicy(), request.Url(), |
| 212 worker_global_scope_->OutgoingReferrer())); |
| 213 request.AddHTTPOriginIfNeeded(worker_global_scope_->GetSecurityOrigin()); |
| 214 } else { |
| 215 DCHECK_EQ(SecurityPolicy::GenerateReferrer(request.GetReferrerPolicy(), |
| 216 request.Url(), |
| 217 request.HttpReferrer()) |
| 218 .referrer, |
| 219 request.HttpReferrer()); |
| 220 request.AddHTTPOriginIfNeeded(request.HttpReferrer()); |
| 221 } |
| 222 } |
| 223 } |
| 224 |
88 void WorkerFetchContext::PrepareRequest(ResourceRequest& request, | 225 void WorkerFetchContext::PrepareRequest(ResourceRequest& request, |
89 RedirectType) { | 226 RedirectType) { |
| 227 String user_agent = worker_global_scope_->UserAgent(); |
| 228 probe::applyUserAgentOverride(worker_global_scope_, &user_agent); |
| 229 DCHECK(!user_agent.IsNull()); |
| 230 request.SetHTTPUserAgent(AtomicString(user_agent)); |
| 231 |
| 232 request.SetIsMojoIPCForced(true); |
| 233 if (request.RequestorOrigin()->IsUnique() && |
| 234 !worker_global_scope_->GetSecurityOrigin()->IsUnique()) { |
| 235 request.SetRequestorOrigin(worker_global_scope_->GetSecurityOrigin()); |
| 236 } |
90 WrappedResourceRequest webreq(request); | 237 WrappedResourceRequest webreq(request); |
91 web_context_->WillSendRequest(webreq); | 238 web_context_->WillSendRequest(webreq); |
92 } | 239 } |
93 | 240 |
| 241 void WorkerFetchContext::DispatchWillSendRequest( |
| 242 unsigned long identifier, |
| 243 ResourceRequest& request, |
| 244 const ResourceResponse& redirect_response, |
| 245 const FetchInitiatorInfo& initiator_info) { |
| 246 probe::willSendRequest(worker_global_scope_, identifier, nullptr, request, |
| 247 redirect_response, initiator_info); |
| 248 } |
| 249 |
| 250 void WorkerFetchContext::DispatchDidReceiveResponse( |
| 251 unsigned long identifier, |
| 252 const ResourceResponse& response, |
| 253 WebURLRequest::FrameType frame_type, |
| 254 WebURLRequest::RequestContext request_context, |
| 255 Resource* resource, |
| 256 ResourceResponseType) { |
| 257 if (response.HasMajorCertificateErrors()) { |
| 258 WebMixedContentContextType context_type = |
| 259 WebMixedContent::ContextTypeFromRequestContext( |
| 260 request_context, false /* strictMixedContentCheckingForPlugin */); |
| 261 if (context_type == WebMixedContentContextType::kBlockable) { |
| 262 web_context_->DidRunContentWithCertificateErrors(response.Url()); |
| 263 } else { |
| 264 web_context_->DidDisplayContentWithCertificateErrors(response.Url()); |
| 265 } |
| 266 } |
| 267 probe::didReceiveResourceResponse(worker_global_scope_, identifier, nullptr, |
| 268 response, resource); |
| 269 } |
| 270 |
| 271 void WorkerFetchContext::DispatchDidReceiveData(unsigned long identifier, |
| 272 const char* data, |
| 273 int data_length) { |
| 274 probe::didReceiveData(worker_global_scope_, identifier, nullptr, data, |
| 275 data_length); |
| 276 } |
| 277 |
| 278 void WorkerFetchContext::DispatchDidReceiveEncodedData( |
| 279 unsigned long identifier, |
| 280 int encoded_data_length) { |
| 281 probe::didReceiveEncodedDataLength(worker_global_scope_, identifier, |
| 282 encoded_data_length); |
| 283 } |
| 284 |
| 285 void WorkerFetchContext::DispatchDidFinishLoading(unsigned long identifier, |
| 286 double finish_time, |
| 287 int64_t encoded_data_length, |
| 288 int64_t decoded_body_length) { |
| 289 probe::didFinishLoading(worker_global_scope_, identifier, nullptr, |
| 290 finish_time, encoded_data_length, |
| 291 decoded_body_length); |
| 292 } |
| 293 |
| 294 void WorkerFetchContext::DispatchDidFail(unsigned long identifier, |
| 295 const ResourceError& error, |
| 296 int64_t encoded_data_length, |
| 297 bool is_internal_request) { |
| 298 probe::didFailLoading(worker_global_scope_, identifier, error); |
| 299 } |
| 300 |
| 301 ResourceRequestBlockedReason WorkerFetchContext::AllowResponse( |
| 302 Resource::Type type, |
| 303 const ResourceRequest& resource_request, |
| 304 const KURL& url, |
| 305 const ResourceLoaderOptions& options) const { |
| 306 ResourceRequestBlockedReason blocked_reason = |
| 307 CanRequestInternal(type, resource_request, url, options, |
| 308 SecurityViolationReportingPolicy::kReport, |
| 309 FetchParameters::kUseDefaultOriginRestrictionForType, |
| 310 RedirectStatus::kFollowedRedirect); |
| 311 if (blocked_reason != ResourceRequestBlockedReason::kNone) { |
| 312 probe::didBlockRequest(worker_global_scope_, resource_request, nullptr, |
| 313 options.initiator_info, blocked_reason); |
| 314 } |
| 315 return blocked_reason; |
| 316 } |
| 317 |
| 318 void WorkerFetchContext::AddResourceTiming(const ResourceTimingInfo& info) { |
| 319 WorkerGlobalScopePerformance::performance(*worker_global_scope_) |
| 320 ->AddResourceTiming(info); |
| 321 } |
| 322 |
| 323 ResourceRequestBlockedReason WorkerFetchContext::CanRequestInternal( |
| 324 Resource::Type type, |
| 325 const ResourceRequest& resource_request, |
| 326 const KURL& url, |
| 327 const ResourceLoaderOptions& options, |
| 328 SecurityViolationReportingPolicy reporting_policy, |
| 329 FetchParameters::OriginRestriction origin_restriction, |
| 330 ResourceRequest::RedirectStatus redirect_status) const { |
| 331 bool should_block_request = false; |
| 332 probe::shouldBlockRequest(worker_global_scope_, resource_request, |
| 333 &should_block_request); |
| 334 if (should_block_request) |
| 335 return ResourceRequestBlockedReason::kInspector; |
| 336 |
| 337 SecurityOrigin* security_origin = options.security_origin.Get(); |
| 338 if (!security_origin) |
| 339 security_origin = worker_global_scope_->GetSecurityOrigin(); |
| 340 if (!security_origin->CanDisplay(url)) { |
| 341 if (origin_restriction == FetchParameters::kRestrictToSameOrigin) { |
| 342 return ResourceRequestBlockedReason::kOrigin; |
| 343 } |
| 344 } |
| 345 |
| 346 if (!url.User().IsEmpty() || !url.Pass().IsEmpty()) { |
| 347 // See https://crbug.com/504300 |
| 348 if (RuntimeEnabledFeatures::blockCredentialedSubresourcesEnabled()) |
| 349 return ResourceRequestBlockedReason::kOrigin; |
| 350 } |
| 351 |
| 352 // TODO(horo): Check GetStrictMixedContentChecking() |
| 353 // TODO(horo): Implement reporting. |
| 354 if (MixedContentChecker::IsMixedContent(security_origin, url)) |
| 355 return ResourceRequestBlockedReason::kMixedContent; |
| 356 |
| 357 // TODO(horo): Implement subresource filter. |
| 358 |
| 359 if (!worker_global_scope_->GetContentSecurityPolicy()->AllowRequest( |
| 360 resource_request.GetRequestContext(), url, |
| 361 options.content_security_policy_nonce, options.integrity_metadata, |
| 362 options.parser_disposition, redirect_status, reporting_policy)) { |
| 363 return ResourceRequestBlockedReason::CSP; |
| 364 } |
| 365 |
| 366 return ResourceRequestBlockedReason::kNone; |
| 367 } |
| 368 |
| 369 RefPtr<WebTaskRunner> WorkerFetchContext::TimerTaskRunner() const { |
| 370 return timer_task_runner_; |
| 371 } |
| 372 |
| 373 RefPtr<WebTaskRunner> WorkerFetchContext::LoadingTaskRunner() const { |
| 374 return loading_task_runner_; |
| 375 } |
| 376 |
| 377 Resource::ResourceCallback* WorkerFetchContext::GetResourceCallback() { |
| 378 return resource_callback_; |
| 379 } |
| 380 |
| 381 DEFINE_TRACE(WorkerFetchContext) { |
| 382 visitor->Trace(worker_global_scope_); |
| 383 visitor->Trace(resource_fetcher_); |
| 384 visitor->Trace(resource_callback_); |
| 385 FetchContext::Trace(visitor); |
| 386 } |
| 387 |
94 void ProvideWorkerFetchContextToWorker( | 388 void ProvideWorkerFetchContextToWorker( |
95 WorkerClients* clients, | 389 WorkerClients* clients, |
96 std::unique_ptr<WebWorkerFetchContext> web_context) { | 390 std::unique_ptr<WebWorkerFetchContext> web_context) { |
97 DCHECK(clients); | 391 DCHECK(clients); |
98 WorkerFetchContextHolder::ProvideTo( | 392 WorkerFetchContextHolder::ProvideTo( |
99 *clients, WorkerFetchContextHolder::SupplementName(), | 393 *clients, WorkerFetchContextHolder::SupplementName(), |
100 new WorkerFetchContextHolder(std::move(web_context))); | 394 new WorkerFetchContextHolder(std::move(web_context))); |
101 } | 395 } |
102 | 396 |
103 } // namespace blink | 397 } // namespace blink |
OLD | NEW |