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