| // 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 |