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