blob: df6186bc60b54bf63616c7579c7c396619fe3de4 [file] [log] [blame]
// 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 "third_party/blink/renderer/core/loader/worker_fetch_context.h"
#include "base/single_thread_task_runner.h"
#include "third_party/blink/public/platform/web_mixed_content.h"
#include "third_party/blink/public/platform/web_mixed_content_context_type.h"
#include "third_party/blink/public/platform/web_url_loader_factory.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/public/platform/web_worker_fetch_context.h"
#include "third_party/blink/renderer/core/frame/deprecation.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
#include "third_party/blink/renderer/core/loader/subresource_filter.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/core/timing/worker_global_scope_performance.h"
#include "third_party/blink/renderer/core/workers/worker_clients.h"
#include "third_party/blink/renderer/core/workers/worker_content_settings_client.h"
#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/platform/exported/wrapped_resource_request.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h"
#include "third_party/blink/renderer/platform/loader/fetch/worker_resource_timing_notifier.h"
#include "third_party/blink/renderer/platform/network/network_state_notifier.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/supplementable.h"
#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
namespace blink {
WorkerFetchContext::~WorkerFetchContext() = default;
WorkerFetchContext::WorkerFetchContext(
WorkerOrWorkletGlobalScope& global_scope,
scoped_refptr<WebWorkerFetchContext> web_context,
SubresourceFilter* subresource_filter,
ContentSecurityPolicy& content_security_policy,
WorkerResourceTimingNotifier* resource_timing_notifier)
: global_scope_(global_scope),
web_context_(std::move(web_context)),
subresource_filter_(subresource_filter),
content_security_policy_(&content_security_policy),
resource_timing_notifier_(resource_timing_notifier),
save_data_enabled_(GetNetworkStateNotifier().SaveDataEnabled()) {
DCHECK(global_scope.IsContextThread());
DCHECK(web_context_);
// TODO(bashi): Add DCHECK for |resource_timing_notifier| once all callsites
// of this ctor pass a valid WorkerResourceTimingNotifier.
}
KURL WorkerFetchContext::GetSiteForCookies() const {
return web_context_->SiteForCookies();
}
scoped_refptr<const SecurityOrigin> WorkerFetchContext::GetTopFrameOrigin()
const {
base::Optional<WebSecurityOrigin> top_frame_origin =
web_context_->TopFrameOrigin();
// The top frame origin of shared and service workers is null.
if (!top_frame_origin) {
DCHECK(global_scope_->IsSharedWorkerGlobalScope() ||
global_scope_->IsServiceWorkerGlobalScope());
return scoped_refptr<const SecurityOrigin>();
}
return *top_frame_origin;
}
SubresourceFilter* WorkerFetchContext::GetSubresourceFilter() const {
return subresource_filter_.Get();
}
PreviewsResourceLoadingHints*
WorkerFetchContext::GetPreviewsResourceLoadingHints() const {
return nullptr;
}
bool WorkerFetchContext::AllowScriptFromSource(const KURL& url) const {
WorkerContentSettingsClient* settings_client =
WorkerContentSettingsClient::From(*global_scope_);
// If we're on a worker, script should be enabled, so no need to plumb
// Settings::GetScriptEnabled() here.
return !settings_client || settings_client->AllowScriptFromSource(true, url);
}
bool WorkerFetchContext::ShouldBlockRequestByInspector(const KURL& url) const {
bool should_block_request = false;
probe::ShouldBlockRequest(Probe(), url, &should_block_request);
return should_block_request;
}
void WorkerFetchContext::DispatchDidBlockRequest(
const ResourceRequest& resource_request,
const FetchInitiatorInfo& fetch_initiator_info,
ResourceRequestBlockedReason blocked_reason,
ResourceType resource_type) const {
probe::DidBlockRequest(Probe(), resource_request, nullptr, Url(),
fetch_initiator_info, blocked_reason, resource_type);
}
bool WorkerFetchContext::ShouldBypassMainWorldCSP() const {
// This method was introduced to bypass the page's CSP while running the
// script from an isolated world (ex: Chrome extensions). But worker threads
// doesn't have any isolated world. So we can just return false.
return false;
}
bool WorkerFetchContext::IsSVGImageChromeClient() const {
return false;
}
void WorkerFetchContext::CountUsage(WebFeature feature) const {
UseCounter::Count(global_scope_, feature);
}
void WorkerFetchContext::CountDeprecation(WebFeature feature) const {
Deprecation::CountDeprecation(global_scope_, feature);
}
CoreProbeSink* WorkerFetchContext::Probe() const {
return probe::ToCoreProbeSink(static_cast<ExecutionContext*>(global_scope_));
}
bool WorkerFetchContext::ShouldBlockWebSocketByMixedContentCheck(
const KURL& url) const {
// Worklets don't support WebSocket.
DCHECK(global_scope_->IsWorkerGlobalScope());
return !MixedContentChecker::IsWebSocketAllowed(*this, url);
}
std::unique_ptr<WebSocketHandshakeThrottle>
WorkerFetchContext::CreateWebSocketHandshakeThrottle() {
return web_context_->CreateWebSocketHandshakeThrottle(
global_scope_->GetTaskRunner(blink::TaskType::kNetworking));
}
bool WorkerFetchContext::ShouldBlockFetchByMixedContentCheck(
mojom::RequestContextType request_context,
ResourceRequest::RedirectStatus redirect_status,
const KURL& url,
SecurityViolationReportingPolicy reporting_policy) const {
return MixedContentChecker::ShouldBlockFetchOnWorker(
*this, request_context, redirect_status, url, reporting_policy,
global_scope_->IsWorkletGlobalScope());
}
bool WorkerFetchContext::ShouldBlockFetchAsCredentialedSubresource(
const ResourceRequest& resource_request,
const KURL& url) const {
if ((!url.User().IsEmpty() || !url.Pass().IsEmpty()) &&
resource_request.GetRequestContext() !=
mojom::RequestContextType::XML_HTTP_REQUEST) {
if (Url().User() != url.User() || Url().Pass() != url.Pass()) {
CountDeprecation(
WebFeature::kRequestedSubresourceWithEmbeddedCredentials);
// TODO(mkwst): Remove the runtime check one way or the other once we're
// sure it's going to stick (or that it's not).
if (RuntimeEnabledFeatures::BlockCredentialedSubresourcesEnabled())
return true;
}
}
return false;
}
const KURL& WorkerFetchContext::Url() const {
return GetResourceFetcherProperties()
.GetFetchClientSettingsObject()
.GlobalObjectUrl();
}
const SecurityOrigin* WorkerFetchContext::GetParentSecurityOrigin() const {
// This method was introduced to check the parent frame's security context
// while loading iframe document resources. So this method is not suitable for
// workers.
NOTREACHED();
return nullptr;
}
const ContentSecurityPolicy* WorkerFetchContext::GetContentSecurityPolicy()
const {
return content_security_policy_;
}
void WorkerFetchContext::AddConsoleMessage(ConsoleMessage* message) const {
return global_scope_->AddConsoleMessage(message);
}
void WorkerFetchContext::PrepareRequest(
ResourceRequest& request,
const FetchInitiatorInfo& initiator_info,
WebScopedVirtualTimePauser&,
ResourceType resource_type) {
String user_agent = global_scope_->UserAgent();
probe::ApplyUserAgentOverride(Probe(), &user_agent);
DCHECK(!user_agent.IsNull());
request.SetHTTPUserAgent(AtomicString(user_agent));
WrappedResourceRequest webreq(request);
web_context_->WillSendRequest(webreq);
probe::PrepareRequest(Probe(), nullptr, request, initiator_info,
resource_type);
}
void WorkerFetchContext::AddAdditionalRequestHeaders(ResourceRequest& request) {
BaseFetchContext::AddAdditionalRequestHeaders(request);
// The remaining modifications are only necessary for HTTP and HTTPS.
if (!request.Url().IsEmpty() && !request.Url().ProtocolIsInHTTPFamily())
return;
if (save_data_enabled_)
request.SetHttpHeaderField(http_names::kSaveData, "on");
}
void WorkerFetchContext::AddResourceTiming(const ResourceTimingInfo& info) {
// TODO(nhiroki): Add ResourceTiming API support once it's spec'ed for
// worklets.
if (global_scope_->IsWorkletGlobalScope())
return;
if (resource_timing_notifier_) {
const SecurityOrigin* security_origin = GetResourceFetcherProperties()
.GetFetchClientSettingsObject()
.GetSecurityOrigin();
WebResourceTimingInfo web_info = Performance::GenerateResourceTiming(
*security_origin, info, *global_scope_);
resource_timing_notifier_->AddResourceTiming(web_info,
info.InitiatorType());
}
}
void WorkerFetchContext::PopulateResourceRequest(
ResourceType type,
const ClientHintsPreferences& hints_preferences,
const FetchParameters::ResourceWidth& resource_width,
ResourceRequest& out_request) {
MixedContentChecker::UpgradeInsecureRequest(
out_request,
&GetResourceFetcherProperties().GetFetchClientSettingsObject(),
global_scope_, network::mojom::RequestContextFrameType::kNone);
SetFirstPartyCookie(out_request);
if (!out_request.TopFrameOrigin())
out_request.SetTopFrameOrigin(GetTopFrameOrigin());
}
void WorkerFetchContext::SetFirstPartyCookie(ResourceRequest& out_request) {
if (out_request.SiteForCookies().IsNull())
out_request.SetSiteForCookies(GetSiteForCookies());
}
WorkerSettings* WorkerFetchContext::GetWorkerSettings() const {
auto* scope = DynamicTo<WorkerGlobalScope>(*global_scope_);
return scope ? scope->GetWorkerSettings() : nullptr;
}
WorkerContentSettingsClient*
WorkerFetchContext::GetWorkerContentSettingsClient() const {
return WorkerContentSettingsClient::From(*global_scope_);
}
void WorkerFetchContext::Trace(blink::Visitor* visitor) {
visitor->Trace(global_scope_);
visitor->Trace(subresource_filter_);
visitor->Trace(content_security_policy_);
BaseFetchContext::Trace(visitor);
}
} // namespace blink