blob: 6707e9902d014e01e041cd2b97491253c5de8a24 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/device_bound_sessions/session_challenge_param.h"
#include "base/ranges/algorithm.h"
#include "net/http/http_response_headers.h"
#include "url/gurl.h"
namespace {
// Sec-Session-Challenge header defined in
// https://github.com/WICG/dbsc/blob/main/README.md#high-level-overview
constexpr char kSessionChallengeHeaderName[] = "Sec-Session-Challenge";
constexpr char kSessionIdKey[] = "id";
} // namespace
namespace net::device_bound_sessions {
SessionChallengeParam::SessionChallengeParam(
SessionChallengeParam&& other) noexcept = default;
SessionChallengeParam& SessionChallengeParam::operator=(
SessionChallengeParam&& other) noexcept = default;
SessionChallengeParam::~SessionChallengeParam() = default;
SessionChallengeParam::SessionChallengeParam(
std::optional<std::string> session_id,
std::string challenge)
: session_id_(std::move(session_id)), challenge_(std::move(challenge)) {}
// static
std::optional<SessionChallengeParam> SessionChallengeParam::ParseItem(
const structured_headers::ParameterizedMember& session_challenge) {
if (session_challenge.member_is_inner_list ||
session_challenge.member.empty()) {
return std::nullopt;
}
const structured_headers::Item& item = session_challenge.member[0].item;
if (!item.is_string()) {
return std::nullopt;
}
std::string challenge(item.GetString());
if (challenge.empty()) {
return std::nullopt;
}
std::optional<std::string> session_id;
if (auto it = base::ranges::find(
session_challenge.params, kSessionIdKey,
&std::pair<std::string, structured_headers::Item>::first);
it != session_challenge.params.end()) {
const auto& param = it->second;
if (!param.is_string()) {
return std::nullopt;
}
auto id = param.GetString();
if (!id.empty()) {
session_id = std::move(id);
}
}
return SessionChallengeParam(std::move(session_id), std::move(challenge));
}
// static
std::vector<SessionChallengeParam> SessionChallengeParam::CreateIfValid(
const GURL& request_url,
const net::HttpResponseHeaders* headers) {
std::vector<SessionChallengeParam> params;
if (!request_url.is_valid()) {
return params;
}
if (!headers) {
return params;
}
std::optional<std::string> header_value =
headers->GetNormalizedHeader(kSessionChallengeHeaderName);
if (!header_value) {
return params;
}
std::optional<structured_headers::List> list =
structured_headers::ParseList(*header_value);
if (!list) {
return params;
}
for (const auto& session_challenge : *list) {
std::optional<SessionChallengeParam> param = ParseItem(session_challenge);
if (param) {
params.push_back(std::move(*param));
}
}
return params;
}
} // namespace net::device_bound_sessions