|
| 1 | +/* Copyright (c) 2022 The Brave Authors. All rights reserved. |
| 2 | + * This Source Code Form is subject to the terms of the Mozilla Public |
| 3 | + * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
| 4 | + * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 5 | + |
| 6 | +#include "brave/browser/net/brave_reduce_language_network_delegate_helper.h" |
| 7 | + |
| 8 | +#include <array> |
| 9 | +#include <string> |
| 10 | +#include <vector> |
| 11 | + |
| 12 | +#include "base/strings/string_split.h" |
| 13 | +#include "brave/browser/brave_browser_process.h" |
| 14 | +#include "brave/components/brave_shields/browser/brave_farbling_service.h" |
| 15 | +#include "brave/components/brave_shields/browser/brave_shields_util.h" |
| 16 | +#include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
| 17 | +#include "chrome/browser/profiles/profile.h" |
| 18 | +#include "components/content_settings/core/browser/host_content_settings_map.h" |
| 19 | +#include "components/language/core/browser/language_prefs.h" |
| 20 | +#include "components/language/core/browser/pref_names.h" |
| 21 | +#include "components/prefs/pref_service.h" |
| 22 | +#include "content/public/browser/browser_context.h" |
| 23 | +#include "net/base/net_errors.h" |
| 24 | + |
| 25 | +using brave_shields::ControlType; |
| 26 | + |
| 27 | +namespace brave { |
| 28 | + |
| 29 | +namespace { |
| 30 | +constexpr char kAcceptLanguageMax[] = "en-US,en;q=0.9"; |
| 31 | +const std::array<std::string, 5> kFakeQValues = {";q=0.5", ";q=0.6", ";q=0.7", |
| 32 | + ";q=0.8", ";q=0.9"}; |
| 33 | +} // namespace |
| 34 | + |
| 35 | +std::string FarbleAcceptLanguageHeader( |
| 36 | + const GURL& tab_origin, |
| 37 | + Profile* profile, |
| 38 | + HostContentSettingsMap* content_settings) { |
| 39 | + std::string languages = |
| 40 | + profile->GetPrefs()->Get(language::prefs::kAcceptLanguages)->GetString(); |
| 41 | + std::string accept_language_string = language::GetFirstLanguage(languages); |
| 42 | + // If the first language is a multi-part code like "en-US" or "zh-HK", |
| 43 | + // extract and append the base language code to |accept_language_string|. |
| 44 | + const std::vector<std::string> tokens = base::SplitString( |
| 45 | + accept_language_string, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
| 46 | + if (!tokens.empty() && tokens[0] != accept_language_string) { |
| 47 | + accept_language_string += "," + tokens[0]; |
| 48 | + } |
| 49 | + // Add a fake q value after the language code. |
| 50 | + brave::FarblingPRNG prng; |
| 51 | + if (g_brave_browser_process->brave_farbling_service() |
| 52 | + ->MakePseudoRandomGeneratorForURL( |
| 53 | + tab_origin, profile && profile->IsOffTheRecord(), &prng)) { |
| 54 | + accept_language_string += kFakeQValues[prng() % kFakeQValues.size()]; |
| 55 | + } |
| 56 | + return accept_language_string; |
| 57 | +} |
| 58 | + |
| 59 | +int OnBeforeStartTransaction_ReduceLanguageWork( |
| 60 | + net::HttpRequestHeaders* headers, |
| 61 | + const ResponseCallback& next_callback, |
| 62 | + std::shared_ptr<BraveRequestInfo> ctx) { |
| 63 | + Profile* profile = Profile::FromBrowserContext(ctx->browser_context); |
| 64 | + DCHECK(profile); |
| 65 | + HostContentSettingsMap* content_settings = |
| 66 | + HostContentSettingsMapFactory::GetForProfile(profile); |
| 67 | + DCHECK(content_settings); |
| 68 | + if (!brave_shields::ShouldDoReduceLanguage(content_settings, ctx->tab_origin, |
| 69 | + profile->GetPrefs())) { |
| 70 | + return net::OK; |
| 71 | + } |
| 72 | + |
| 73 | + std::string accept_language_string; |
| 74 | + switch (brave_shields::GetFingerprintingControlType(content_settings, |
| 75 | + ctx->tab_origin)) { |
| 76 | + case ControlType::BLOCK: { |
| 77 | + // If fingerprint blocking is maximum, set Accept-Language header to |
| 78 | + // static value regardless of other preferences. |
| 79 | + accept_language_string = kAcceptLanguageMax; |
| 80 | + break; |
| 81 | + } |
| 82 | + case ControlType::DEFAULT: { |
| 83 | + // If fingerprint blocking is default, compute Accept-Language header |
| 84 | + // based on user preferences and some randomization. |
| 85 | + accept_language_string = FarbleAcceptLanguageHeader( |
| 86 | + ctx->tab_origin, profile, content_settings); |
| 87 | + break; |
| 88 | + } |
| 89 | + default: |
| 90 | + // Other cases are handled within ShouldDoReduceLanguage, so we should |
| 91 | + // never reach here. |
| 92 | + NOTREACHED(); |
| 93 | + } |
| 94 | + |
| 95 | + headers->SetHeader(net::HttpRequestHeaders::kAcceptLanguage, |
| 96 | + accept_language_string); |
| 97 | + ctx->set_headers.insert(net::HttpRequestHeaders::kAcceptLanguage); |
| 98 | + |
| 99 | + return net::OK; |
| 100 | +} |
| 101 | + |
| 102 | +} // namespace brave |
0 commit comments