blob: 1986512ebd1a639cecda5c665b5123c39b245f2a [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/network/public/cpp/variants_header_parser.h"
#include <utility>
#include <vector>
#include "base/containers/flat_set.h"
#include "base/no_destructor.h"
#include "net/http/structured_headers.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace network {
// Add Support Variants for existing content negotiation mechanisms, See
// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-variants-06#appendix-A.
// For reduce accept-language fingerprinting, we only care about accept-language
// header.
SupportedVariantsNameSet MakeSupportedVariantsNameSet() {
return {"accept-language"};
}
const SupportedVariantsNameSet& GetSupportedVariantsNameSet() {
static const base::NoDestructor<SupportedVariantsNameSet> set(
MakeSupportedVariantsNameSet());
return *set;
}
absl::optional<std::vector<mojom::VariantsHeaderPtr>> ParseVariantsHeaders(
const std::string& header) {
// Variants is a sh-dictionary of tokens to header; see:
// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-variants-06#section-2
absl::optional<net::structured_headers::Dictionary> maybe_dictionary =
net::structured_headers::ParseDictionary(base::ToLowerASCII(header));
if (!maybe_dictionary.has_value())
return absl::nullopt;
std::vector<mojom::VariantsHeaderPtr> parsed_headers;
// Now filter only supported variants.
const SupportedVariantsNameSet& supported_set = GetSupportedVariantsNameSet();
for (const auto& dictionary_pair : maybe_dictionary.value()) {
if (!supported_set.count(dictionary_pair.first))
continue;
std::vector<std::string> parsed_values;
for (const auto& member : dictionary_pair.second.member) {
if (!member.item.is_token())
continue;
parsed_values.push_back(member.item.GetString());
}
auto parsed = mojom::VariantsHeader::New(dictionary_pair.first,
std::move(parsed_values));
parsed_headers.push_back(std::move(parsed));
}
return absl::make_optional(std::move(parsed_headers));
}
} // namespace network