xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/quic_stream_priority.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2022 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/quic/core/quic_stream_priority.h"
6 
7 #include "quiche/common/platform/api/quiche_bug_tracker.h"
8 #include "quiche/common/structured_headers.h"
9 
10 namespace quic {
11 
SerializePriorityFieldValue(HttpStreamPriority priority)12 std::string SerializePriorityFieldValue(HttpStreamPriority priority) {
13   quiche::structured_headers::Dictionary dictionary;
14 
15   if (priority.urgency != HttpStreamPriority::kDefaultUrgency &&
16       priority.urgency >= HttpStreamPriority::kMinimumUrgency &&
17       priority.urgency <= HttpStreamPriority::kMaximumUrgency) {
18     dictionary[HttpStreamPriority::kUrgencyKey] =
19         quiche::structured_headers::ParameterizedMember(
20             quiche::structured_headers::Item(
21                 static_cast<int64_t>(priority.urgency)),
22             {});
23   }
24 
25   if (priority.incremental != HttpStreamPriority::kDefaultIncremental) {
26     dictionary[HttpStreamPriority::kIncrementalKey] =
27         quiche::structured_headers::ParameterizedMember(
28             quiche::structured_headers::Item(priority.incremental), {});
29   }
30 
31   std::optional<std::string> priority_field_value =
32       quiche::structured_headers::SerializeDictionary(dictionary);
33   if (!priority_field_value.has_value()) {
34     QUICHE_BUG(priority_field_value_serialization_failed);
35     return "";
36   }
37 
38   return *priority_field_value;
39 }
40 
ParsePriorityFieldValue(absl::string_view priority_field_value)41 std::optional<HttpStreamPriority> ParsePriorityFieldValue(
42     absl::string_view priority_field_value) {
43   std::optional<quiche::structured_headers::Dictionary> parsed_dictionary =
44       quiche::structured_headers::ParseDictionary(priority_field_value);
45   if (!parsed_dictionary.has_value()) {
46     return std::nullopt;
47   }
48 
49   uint8_t urgency = HttpStreamPriority::kDefaultUrgency;
50   bool incremental = HttpStreamPriority::kDefaultIncremental;
51 
52   for (const auto& [name, value] : *parsed_dictionary) {
53     if (value.member_is_inner_list) {
54       continue;
55     }
56 
57     const std::vector<quiche::structured_headers::ParameterizedItem>& member =
58         value.member;
59     if (member.size() != 1) {
60       // If `member_is_inner_list` is false above,
61       // then `member` should have exactly one element.
62       QUICHE_BUG(priority_field_value_parsing_internal_error);
63       continue;
64     }
65 
66     const quiche::structured_headers::Item item = member[0].item;
67     if (name == HttpStreamPriority::kUrgencyKey && item.is_integer()) {
68       int parsed_urgency = item.GetInteger();
69       // Ignore out-of-range values.
70       if (parsed_urgency >= HttpStreamPriority::kMinimumUrgency &&
71           parsed_urgency <= HttpStreamPriority::kMaximumUrgency) {
72         urgency = parsed_urgency;
73       }
74     } else if (name == HttpStreamPriority::kIncrementalKey &&
75                item.is_boolean()) {
76       incremental = item.GetBoolean();
77     }
78   }
79 
80   return HttpStreamPriority{urgency, incremental};
81 }
82 
83 }  // namespace quic
84