1 // Copyright 2015 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 "third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h"
6
7 #include "base/macros.h"
8 #include "third_party/blink/public/common/client_hints/client_hints.h"
9 #include "third_party/blink/renderer/platform/network/http_names.h"
10 #include "third_party/blink/renderer/platform/network/http_parsers.h"
11 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
12 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
13 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
14
15 namespace blink {
16
ClientHintsPreferences()17 ClientHintsPreferences::ClientHintsPreferences() {
18 DCHECK_EQ(static_cast<size_t>(mojom::WebClientHintsType::kMaxValue) + 1,
19 kClientHintsMappingsCount);
20 }
21
UpdateFrom(const ClientHintsPreferences & preferences)22 void ClientHintsPreferences::UpdateFrom(
23 const ClientHintsPreferences& preferences) {
24 for (size_t i = 0;
25 i < static_cast<int>(mojom::WebClientHintsType::kMaxValue) + 1; ++i) {
26 mojom::WebClientHintsType type = static_cast<mojom::WebClientHintsType>(i);
27 enabled_hints_.SetIsEnabled(type, preferences.ShouldSend(type));
28 }
29 }
30
UpdateFromAcceptClientHintsHeader(const String & header_value,const KURL & url,Context * context)31 void ClientHintsPreferences::UpdateFromAcceptClientHintsHeader(
32 const String& header_value,
33 const KURL& url,
34 Context* context) {
35 if (header_value.IsEmpty())
36 return;
37
38 // Client hints should be allowed only on secure URLs.
39 if (!IsClientHintsAllowed(url))
40 return;
41
42 // 8-bit conversions from String can turn non-ASCII characters into ?,
43 // turning syntax errors into "correct" syntax, so reject those first.
44 // (.Utf8() doesn't have this problem, but it does a lot of expensive
45 // work that would be wasted feeding to an ASCII-only syntax).
46 if (!header_value.ContainsOnlyASCIIOrEmpty())
47 return;
48
49 // Note: .Ascii() would convert tab to ?, which is undesirable.
50 base::Optional<std::vector<blink::mojom::WebClientHintsType>> parsed_ch =
51 ParseAcceptCH(header_value.Latin1(),
52 RuntimeEnabledFeatures::LangClientHintHeaderEnabled(),
53 RuntimeEnabledFeatures::UserAgentClientHintEnabled());
54 if (!parsed_ch.has_value())
55 return;
56
57 // Note: this keeps previously enabled hints.
58 for (blink::mojom::WebClientHintsType newly_enabled : parsed_ch.value())
59 enabled_hints_.SetIsEnabled(newly_enabled, true);
60
61 if (context) {
62 for (size_t i = 0;
63 i < static_cast<int>(mojom::WebClientHintsType::kMaxValue) + 1; ++i) {
64 mojom::WebClientHintsType type =
65 static_cast<mojom::WebClientHintsType>(i);
66 if (enabled_hints_.IsEnabled(type))
67 context->CountClientHints(type);
68 }
69 }
70 }
71
UpdateFromAcceptClientHintsLifetimeHeader(const String & header_value,const KURL & url,Context * context)72 void ClientHintsPreferences::UpdateFromAcceptClientHintsLifetimeHeader(
73 const String& header_value,
74 const KURL& url,
75 Context* context) {
76 if (header_value.IsEmpty())
77 return;
78
79 // Client hints should be allowed only on secure URLs.
80 if (!IsClientHintsAllowed(url))
81 return;
82
83 bool conversion_ok = false;
84 int64_t persist_duration_seconds = header_value.ToInt64Strict(&conversion_ok);
85 if (!conversion_ok || persist_duration_seconds <= 0)
86 return;
87
88 persist_duration_ = base::TimeDelta::FromSeconds(persist_duration_seconds);
89 if (context)
90 context->CountPersistentClientHintHeaders();
91 }
92
93 // static
IsClientHintsAllowed(const KURL & url)94 bool ClientHintsPreferences::IsClientHintsAllowed(const KURL& url) {
95 return (url.ProtocolIs("http") || url.ProtocolIs("https")) &&
96 (SecurityOrigin::IsSecure(url) ||
97 SecurityOrigin::Create(url)->IsLocalhost());
98 }
99
GetWebEnabledClientHints() const100 WebEnabledClientHints ClientHintsPreferences::GetWebEnabledClientHints() const {
101 return enabled_hints_;
102 }
103
GetPersistDuration() const104 base::TimeDelta ClientHintsPreferences::GetPersistDuration() const {
105 return persist_duration_;
106 }
107
108 } // namespace blink
109