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