Avoid quadratic linear scans in HTTP structured headers parsing.

Use `absl::flat_hash_map` in `ReadDictionary` and `ReadParameters` to track key indices, avoiding quadratic linear scans on adversarial inputs with many distinct or duplicate keys while preserving insertion order.

PiperOrigin-RevId: 1000910914
diff --git a/quiche/common/structured_headers.cc b/quiche/common/structured_headers.cc
index 4332b8a..f7a24a5 100644
--- a/quiche/common/structured_headers.cc
+++ b/quiche/common/structured_headers.cc
@@ -15,7 +15,7 @@
 
 #include "absl/algorithm/container.h"
 #include "absl/base/attributes.h"
-#include "absl/container/flat_hash_set.h"
+#include "absl/container/flat_hash_map.h"
 #include "absl/functional/overload.h"
 #include "absl/strings/ascii.h"
 #include "absl/strings/escaping.h"
@@ -211,7 +211,10 @@
   // Parses a Dictionary ([RFC8941] 4.2.2).
   std::optional<Dictionary> ReadDictionary() {
     QUICHE_CHECK_EQ(version_, kFinal);
-    Dictionary members;
+    std::vector<DictionaryMember> members;
+    // Maps each key to its index in `members` so duplicate keys can overwrite
+    // the existing value in O(1) time while preserving insertion order.
+    absl::flat_hash_map<absl::string_view, size_t> keys;
     while (!input_.empty()) {
       std::optional<absl::string_view> key(ReadKey());
       if (!key) return std::nullopt;
@@ -224,14 +227,19 @@
         if (!parameters) return std::nullopt;
         member = ParameterizedMember(Item(true), std::move(*parameters));
       }
-      members[*key] = std::move(*member);
+      auto [it, inserted] = keys.try_emplace(*key, members.size());
+      if (inserted) {
+        members.emplace_back(*key, *std::move(member));
+      } else {
+        members[it->second].second = *std::move(member);
+      }
       SkipOWS();
       if (input_.empty()) break;
       if (!ConsumeChar(',')) return std::nullopt;
       SkipOWS();
       if (input_.empty()) return std::nullopt;
     }
-    return members;
+    return Dictionary(std::move(members));
   }
 
   // Parses a Parameterised List ([SH09] 4.2.5).
@@ -298,14 +306,16 @@
   // Parses Parameters ([RFC8941] 4.2.3.2)
   std::optional<Parameters> ReadParameters() {
     Parameters parameters;
-    absl::flat_hash_set<absl::string_view> keys;
+    // Maps each parameter name to its index in `parameters` so duplicate keys
+    // can overwrite the existing value in O(1) time while preserving insertion
+    // order.
+    absl::flat_hash_map<absl::string_view, size_t> keys;
 
     while (ConsumeChar(';')) {
       SkipWhitespaces();
 
       std::optional<absl::string_view> name = ReadKey();
       if (!name) return std::nullopt;
-      bool is_duplicate_key = !keys.insert(*name).second;
 
       Item value{true};
       if (ConsumeChar('=')) {
@@ -313,15 +323,11 @@
         if (!item) return std::nullopt;
         value = std::move(*item);
       }
-      if (is_duplicate_key) {
-        for (auto& param : parameters) {
-          if (param.first == name) {
-            param.second = std::move(value);
-            break;
-          }
-        }
-      } else {
+      auto [it, inserted] = keys.try_emplace(*name, parameters.size());
+      if (inserted) {
         parameters.emplace_back(*name, std::move(value));
+      } else {
+        parameters[it->second].second = std::move(value);
       }
     }
     return parameters;