Move quiche/common/balsa to quiche/balsa.

PiperOrigin-RevId: 448235250
diff --git a/quiche/balsa/header_properties.cc b/quiche/balsa/header_properties.cc
new file mode 100644
index 0000000..240979c
--- /dev/null
+++ b/quiche/balsa/header_properties.cc
@@ -0,0 +1,111 @@
+#include "quiche/balsa/header_properties.h"
+
+#include <array>
+
+#include "absl/container/flat_hash_set.h"
+#include "absl/strings/string_view.h"
+#include "quiche/common/quiche_text_utils.h"
+
+namespace quiche::header_properties {
+
+namespace {
+
+using MultivaluedHeadersSet =
+    absl::flat_hash_set<absl::string_view, StringPieceCaseHash,
+                        StringPieceCaseEqual>;
+
+MultivaluedHeadersSet* buildMultivaluedHeaders() {
+  return new MultivaluedHeadersSet({
+      "accept",
+      "accept-charset",
+      "accept-encoding",
+      "accept-language",
+      "accept-ranges",
+      // The follow four headers are all CORS standard headers
+      "access-control-allow-headers",
+      "access-control-allow-methods",
+      "access-control-expose-headers",
+      "access-control-request-headers",
+      "allow",
+      "cache-control",
+      // IETF draft makes this have cache-control syntax
+      "cdn-cache-control",
+      "connection",
+      "content-encoding",
+      "content-language",
+      "expect",
+      "if-match",
+      "if-none-match",
+      // See RFC 5988 section 5
+      "link",
+      "pragma",
+      "proxy-authenticate",
+      "te",
+      // Used in the opening handshake of the WebSocket protocol.
+      "sec-websocket-extensions",
+      // Not mentioned in RFC 2616, but it can have multiple values.
+      "set-cookie",
+      "trailer",
+      "transfer-encoding",
+      "upgrade",
+      "vary",
+      "via",
+      "warning",
+      "www-authenticate",
+      // De facto standard not in the RFCs
+      "x-forwarded-for",
+      // Internal Google usage gives this cache-control syntax
+      "x-go" /**/ "ogle-cache-control",
+  });
+}
+
+std::array<bool, 256> buildInvalidHeaderKeyCharLookupTable() {
+  std::array<bool, 256> invalidCharTable;
+  invalidCharTable.fill(false);
+  for (uint8_t c : kInvalidHeaderKeyCharList) {
+    invalidCharTable[c] = true;
+  }
+  return invalidCharTable;
+}
+
+std::array<bool, 256> buildInvalidCharLookupTable() {
+  std::array<bool, 256> invalidCharTable;
+  invalidCharTable.fill(false);
+  for (uint8_t c : kInvalidHeaderCharList) {
+    invalidCharTable[c] = true;
+  }
+  return invalidCharTable;
+}
+
+}  // anonymous namespace
+
+bool IsMultivaluedHeader(absl::string_view header) {
+  static const MultivaluedHeadersSet* const multivalued_headers =
+      buildMultivaluedHeaders();
+  return multivalued_headers->contains(header);
+}
+
+bool IsInvalidHeaderKeyChar(uint8_t c) {
+  static const std::array<bool, 256> invalidHeaderKeyCharTable =
+      buildInvalidHeaderKeyCharLookupTable();
+
+  return invalidHeaderKeyCharTable[c];
+}
+
+bool IsInvalidHeaderChar(uint8_t c) {
+  static const std::array<bool, 256> invalidCharTable =
+      buildInvalidCharLookupTable();
+
+  return invalidCharTable[c];
+}
+
+bool HasInvalidHeaderChars(absl::string_view value) {
+  for (const char c : value) {
+    if (IsInvalidHeaderChar(c)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace quiche::header_properties