| // Copyright 2014 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 "content/public/common/referrer.h" |
| |
| #include <atomic> |
| #include <string> |
| |
| #include "base/numerics/safe_conversions.h" |
| #include "content/public/common/content_features.h" |
| #include "content/public/common/content_switches.h" |
| #include "mojo/public/cpp/bindings/enum_utils.h" |
| #include "net/base/features.h" |
| #include "net/url_request/url_request_job.h" |
| #include "services/network/public/cpp/features.h" |
| #include "services/network/public/cpp/resource_request.h" |
| #include "services/network/public/mojom/referrer_policy.mojom-shared.h" |
| #include "third_party/blink/public/mojom/referrer.mojom.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| // Using an atomic is necessary because this code is called from both the |
| // browser and the renderer (so that access is not on a single sequence when in |
| // single-process mode), and because it is called from multiple threads within |
| // the renderer. |
| bool ReadModifyWriteForceLegacyPolicyFlag( |
| base::Optional<bool> maybe_new_value) { |
| // Default to false in the browser process (it is not expected |
| // that the browser will be provided this switch). |
| // The value is propagated to other processes through the command line. |
| DCHECK(base::CommandLine::InitializedForCurrentProcess()); |
| static std::atomic<bool> value( |
| base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kForceLegacyDefaultReferrerPolicy)); |
| if (!maybe_new_value.has_value()) |
| return value; |
| return value.exchange(*maybe_new_value); |
| } |
| |
| } // namespace |
| |
| Referrer::Referrer(const blink::mojom::Referrer& referrer) |
| : url(referrer.url), policy(referrer.policy) {} |
| |
| // static |
| Referrer Referrer::SanitizeForRequest(const GURL& request, |
| const Referrer& referrer) { |
| blink::mojom::ReferrerPtr sanitized_referrer = SanitizeForRequest( |
| request, blink::mojom::Referrer(referrer.url, referrer.policy)); |
| return Referrer(sanitized_referrer->url, sanitized_referrer->policy); |
| } |
| |
| // static |
| blink::mojom::ReferrerPtr Referrer::SanitizeForRequest( |
| const GURL& request, |
| const blink::mojom::Referrer& referrer) { |
| network::mojom::ReferrerPolicy effective_policy = referrer.policy; |
| if (effective_policy == network::mojom::ReferrerPolicy::kDefault) { |
| effective_policy = |
| NetReferrerPolicyToBlinkReferrerPolicy(GetDefaultReferrerPolicy()); |
| } |
| DCHECK_NE(effective_policy, network::mojom::ReferrerPolicy::kDefault); |
| |
| return blink::mojom::Referrer::New( |
| net::URLRequestJob::ComputeReferrerForPolicy( |
| ReferrerPolicyForUrlRequest(effective_policy), |
| referrer.url /* original_referrer */, request /* destination */), |
| effective_policy); |
| } |
| |
| // static |
| url::Origin Referrer::SanitizeOriginForRequest( |
| const GURL& request, |
| const url::Origin& initiator, |
| network::mojom::ReferrerPolicy policy) { |
| Referrer fake_referrer(initiator.GetURL(), policy); |
| Referrer sanitized_referrer = SanitizeForRequest(request, fake_referrer); |
| return url::Origin::Create(sanitized_referrer.url); |
| } |
| |
| // static |
| net::ReferrerPolicy Referrer::ReferrerPolicyForUrlRequest( |
| network::mojom::ReferrerPolicy referrer_policy) { |
| if (referrer_policy == network::mojom::ReferrerPolicy::kDefault) { |
| return GetDefaultReferrerPolicy(); |
| } |
| return network::ReferrerPolicyForUrlRequest(referrer_policy); |
| } |
| |
| // static |
| network::mojom::ReferrerPolicy Referrer::NetReferrerPolicyToBlinkReferrerPolicy( |
| net::ReferrerPolicy net_policy) { |
| switch (net_policy) { |
| case net::ReferrerPolicy::CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE: |
| return network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade; |
| case net::ReferrerPolicy::REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN: |
| return network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin; |
| case net::ReferrerPolicy::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN: |
| return network::mojom::ReferrerPolicy::kOriginWhenCrossOrigin; |
| case net::ReferrerPolicy::NEVER_CLEAR: |
| return network::mojom::ReferrerPolicy::kAlways; |
| case net::ReferrerPolicy::ORIGIN: |
| return network::mojom::ReferrerPolicy::kOrigin; |
| case net::ReferrerPolicy::CLEAR_ON_TRANSITION_CROSS_ORIGIN: |
| return network::mojom::ReferrerPolicy::kSameOrigin; |
| case net::ReferrerPolicy:: |
| ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE: |
| return network::mojom::ReferrerPolicy::kStrictOrigin; |
| case net::ReferrerPolicy::NO_REFERRER: |
| return network::mojom::ReferrerPolicy::kNever; |
| } |
| NOTREACHED(); |
| return network::mojom::ReferrerPolicy::kDefault; |
| } |
| |
| // static |
| net::ReferrerPolicy Referrer::GetDefaultReferrerPolicy() { |
| // The ReducedReferrerGranularity feature sets the default referrer |
| // policy to strict-origin-when-cross-origin unless forbidden |
| // by the "force legacy policy" global. |
| // TODO(M82, crbug.com/1016541) Once the pertinent enterprise policy has |
| // been removed, update this to remove the global. |
| |
| // Short-circuit to avoid acquiring the lock unless necessary. |
| if (!base::FeatureList::IsEnabled(features::kReducedReferrerGranularity)) |
| return net::ReferrerPolicy::CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE; |
| |
| return ShouldForceLegacyDefaultReferrerPolicy() |
| ? net::ReferrerPolicy::CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE |
| : net::ReferrerPolicy:: |
| REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN; |
| } |
| |
| // static |
| void Referrer::SetForceLegacyDefaultReferrerPolicy(bool force) { |
| ReadModifyWriteForceLegacyPolicyFlag(force); |
| } |
| |
| // static |
| bool Referrer::ShouldForceLegacyDefaultReferrerPolicy() { |
| return ReadModifyWriteForceLegacyPolicyFlag(base::nullopt); |
| } |
| |
| // static |
| network::mojom::ReferrerPolicy Referrer::ConvertToPolicy(int32_t policy) { |
| return mojo::ConvertIntToMojoEnum<network::mojom::ReferrerPolicy>(policy) |
| .value_or(network::mojom::ReferrerPolicy::kDefault); |
| } |
| |
| } // namespace content |