blob: 726cc1710e17690663602521bb6114be2f11e93c [file] [log] [blame] [edit]
// Copyright 2022 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 "quiche/quic/core/quic_stream_priority.h"
#include <optional>
#include <string>
#include <vector>
#include "quiche/common/platform/api/quiche_bug_tracker.h"
#include "quiche/common/structured_headers.h"
namespace quic {
std::string SerializePriorityFieldValue(HttpStreamPriority priority) {
quiche::structured_headers::Dictionary dictionary;
if (priority.urgency != HttpStreamPriority::kDefaultUrgency &&
priority.urgency >= HttpStreamPriority::kMinimumUrgency &&
priority.urgency <= HttpStreamPriority::kMaximumUrgency) {
dictionary[HttpStreamPriority::kUrgencyKey] =
quiche::structured_headers::ParameterizedMember(
quiche::structured_headers::Item(
static_cast<int64_t>(priority.urgency)),
{});
}
if (priority.incremental != HttpStreamPriority::kDefaultIncremental) {
dictionary[HttpStreamPriority::kIncrementalKey] =
quiche::structured_headers::ParameterizedMember(
quiche::structured_headers::Item(priority.incremental), {});
}
std::optional<std::string> priority_field_value =
quiche::structured_headers::SerializeDictionary(dictionary);
if (!priority_field_value.has_value()) {
QUICHE_BUG(priority_field_value_serialization_failed);
return "";
}
return *priority_field_value;
}
std::optional<HttpStreamPriority> ParsePriorityFieldValue(
absl::string_view priority_field_value) {
std::optional<quiche::structured_headers::Dictionary> parsed_dictionary =
quiche::structured_headers::ParseDictionary(priority_field_value);
if (!parsed_dictionary.has_value()) {
return std::nullopt;
}
uint8_t urgency = HttpStreamPriority::kDefaultUrgency;
bool incremental = HttpStreamPriority::kDefaultIncremental;
for (const auto& [name, value] : *parsed_dictionary) {
if (value.member_is_inner_list) {
continue;
}
const std::vector<quiche::structured_headers::ParameterizedItem>& member =
value.member;
if (member.size() != 1) {
// If `member_is_inner_list` is false above,
// then `member` should have exactly one element.
QUICHE_BUG(priority_field_value_parsing_internal_error);
continue;
}
const quiche::structured_headers::Item item = member[0].item;
if (name == HttpStreamPriority::kUrgencyKey && item.is_integer()) {
int parsed_urgency = item.GetInteger();
// Ignore out-of-range values.
if (parsed_urgency >= HttpStreamPriority::kMinimumUrgency &&
parsed_urgency <= HttpStreamPriority::kMaximumUrgency) {
urgency = parsed_urgency;
}
} else if (name == HttpStreamPriority::kIncrementalKey &&
item.is_boolean()) {
incremental = item.GetBoolean();
}
}
return HttpStreamPriority{urgency, incremental};
}
} // namespace quic