blob: 88f65dec56afc99ba8ea09f505ec76dbd13696d5 [file] [log] [blame]
// Copyright 2015 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 "platform/loader/fetch/ClientHintsPreferences.h"
#include "base/macros.h"
#include "platform/HTTPNames.h"
#include "platform/loader/fetch/ResourceResponse.h"
#include "platform/network/HTTPParsers.h"
#include "platform/runtime_enabled_features.h"
#include "platform/weborigin/KURL.h"
#include "third_party/WebKit/common/client_hints/client_hints.h"
namespace blink {
namespace {
void ParseAcceptChHeader(const String& header_value,
WebEnabledClientHints& enabled_hints) {
CommaDelimitedHeaderSet accept_client_hints_header;
ParseCommaDelimitedHeader(header_value, accept_client_hints_header);
for (size_t i = 0; i < static_cast<int>(mojom::WebClientHintsType::kLast) + 1;
++i) {
enabled_hints.SetIsEnabled(
static_cast<mojom::WebClientHintsType>(i),
accept_client_hints_header.Contains(kClientHintsHeaderMapping[i]));
}
enabled_hints.SetIsEnabled(
mojom::WebClientHintsType::kDeviceMemory,
enabled_hints.IsEnabled(mojom::WebClientHintsType::kDeviceMemory) &&
RuntimeEnabledFeatures::DeviceMemoryHeaderEnabled());
}
} // namespace
ClientHintsPreferences::ClientHintsPreferences() {
DCHECK_EQ(static_cast<size_t>(mojom::WebClientHintsType::kLast) + 1,
kClientHintsHeaderMappingCount);
}
void ClientHintsPreferences::UpdateFrom(
const ClientHintsPreferences& preferences) {
for (size_t i = 0; i < static_cast<int>(mojom::WebClientHintsType::kLast) + 1;
++i) {
mojom::WebClientHintsType type = static_cast<mojom::WebClientHintsType>(i);
enabled_hints_.SetIsEnabled(type, preferences.ShouldSend(type));
}
}
void ClientHintsPreferences::UpdateFromAcceptClientHintsHeader(
const String& header_value,
Context* context) {
if (!RuntimeEnabledFeatures::ClientHintsEnabled() || header_value.IsEmpty())
return;
WebEnabledClientHints new_enabled_types;
ParseAcceptChHeader(header_value, new_enabled_types);
for (size_t i = 0; i < static_cast<int>(mojom::WebClientHintsType::kLast) + 1;
++i) {
mojom::WebClientHintsType type = static_cast<mojom::WebClientHintsType>(i);
enabled_hints_.SetIsEnabled(type, enabled_hints_.IsEnabled(type) ||
new_enabled_types.IsEnabled(type));
}
if (context) {
for (size_t i = 0;
i < static_cast<int>(mojom::WebClientHintsType::kLast) + 1; ++i) {
mojom::WebClientHintsType type =
static_cast<mojom::WebClientHintsType>(i);
if (enabled_hints_.IsEnabled(type))
context->CountClientHints(type);
}
}
}
// static
void ClientHintsPreferences::UpdatePersistentHintsFromHeaders(
const ResourceResponse& response,
Context* context,
WebEnabledClientHints& enabled_hints,
TimeDelta* persist_duration) {
*persist_duration = base::TimeDelta();
if (response.WasCached())
return;
String accept_ch_header_value =
response.HttpHeaderField(HTTPNames::Accept_CH);
String accept_ch_lifetime_header_value =
response.HttpHeaderField(HTTPNames::Accept_CH_Lifetime);
if (!RuntimeEnabledFeatures::ClientHintsEnabled() ||
!RuntimeEnabledFeatures::ClientHintsPersistentEnabled() ||
accept_ch_header_value.IsEmpty() ||
accept_ch_lifetime_header_value.IsEmpty()) {
return;
}
const KURL url = response.Url();
if (url.Protocol() != "https") {
// Only HTTPS domains are allowed to persist client hints.
return;
}
bool conversion_ok = false;
int64_t persist_duration_seconds =
accept_ch_lifetime_header_value.ToInt64Strict(&conversion_ok);
if (!conversion_ok || persist_duration_seconds <= 0)
return;
*persist_duration = TimeDelta::FromSeconds(persist_duration_seconds);
if (context)
context->CountPersistentClientHintHeaders();
ParseAcceptChHeader(accept_ch_header_value, enabled_hints);
}
} // namespace blink