Use static char maps in HeaderValidator::ValidateSingleHeader().
When validating header names/values against allowed characters,
switching to static char maps may help with performance.
This CL is otherwise not a functional change.
PiperOrigin-RevId: 425681702
diff --git a/http2/adapter/header_validator.cc b/http2/adapter/header_validator.cc
index dd605f4..470b9f7 100644
--- a/http2/adapter/header_validator.cc
+++ b/http2/adapter/header_validator.cc
@@ -1,5 +1,7 @@
#include "http2/adapter/header_validator.h"
+#include <array>
+
#include "absl/strings/escaping.h"
#include "absl/strings/numbers.h"
#include "common/platform/api/quiche_logging.h"
@@ -25,26 +27,51 @@
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~%!$&'()["
"]*+,;=:";
-// Returns whether `authority` contains only characters from the `host` ABNF
-// from RFC 3986 section 3.2.2.
-bool IsValidAuthority(absl::string_view authority) {
- static const bool* valid_chars = []() {
- using ValidCharArray = bool[256];
- bool* chars = new ValidCharArray;
- memset(chars, 0, sizeof(ValidCharArray));
- for (char c : kValidAuthorityChars) {
- chars[static_cast<uint8_t>(c)] = true;
- }
- return chars;
- }();
- for (char c : authority) {
- if (!valid_chars[static_cast<uint8_t>(c)]) {
+using CharMap = std::array<bool, 256>;
+
+CharMap BuildValidCharMap(absl::string_view valid_chars) {
+ CharMap map;
+ map.fill(false);
+ for (char c : valid_chars) {
+ map[c] = true;
+ }
+ return map;
+}
+
+bool AllCharsInMap(absl::string_view str, const CharMap& map) {
+ for (char c : str) {
+ if (!map[c]) {
return false;
}
}
return true;
}
+// Returns whether `authority` contains only characters from the `host` ABNF
+// from RFC 3986 section 3.2.2.
+bool IsValidAuthority(absl::string_view authority) {
+ static const CharMap valid_chars = BuildValidCharMap(kValidAuthorityChars);
+ return AllCharsInMap(authority, valid_chars);
+}
+
+bool IsValidHeaderName(absl::string_view name) {
+ static const CharMap valid_chars =
+ BuildValidCharMap(kHttp2HeaderNameAllowedChars);
+ return AllCharsInMap(name, valid_chars);
+}
+
+bool IsValidHeaderValue(absl::string_view value) {
+ static const CharMap valid_chars =
+ BuildValidCharMap(kHttp2HeaderValueAllowedChars);
+ return AllCharsInMap(value, valid_chars);
+}
+
+bool IsValidStatus(absl::string_view status) {
+ static const CharMap valid_chars =
+ BuildValidCharMap(kHttp2StatusValueAllowedChars);
+ return AllCharsInMap(status, valid_chars);
+}
+
bool ValidateRequestHeaders(const std::vector<std::string>& pseudo_headers,
absl::string_view method, absl::string_view path,
bool allow_connect) {
@@ -112,23 +139,19 @@
return HEADER_FIELD_TOO_LONG;
}
const absl::string_view validated_key = key[0] == ':' ? key.substr(1) : key;
- if (validated_key.find_first_not_of(kHttp2HeaderNameAllowedChars) !=
- absl::string_view::npos) {
+ if (!IsValidHeaderName(validated_key)) {
QUICHE_VLOG(2) << "invalid chars in header name: ["
<< absl::CEscape(validated_key) << "]";
return HEADER_FIELD_INVALID;
}
- if (value.find_first_not_of(kHttp2HeaderValueAllowedChars) !=
- absl::string_view::npos) {
+ if (!IsValidHeaderValue(value)) {
QUICHE_VLOG(2) << "invalid chars in header value: [" << absl::CEscape(value)
<< "]";
return HEADER_FIELD_INVALID;
}
if (key[0] == ':') {
if (key == ":status") {
- if (value.size() != 3 ||
- value.find_first_not_of(kHttp2StatusValueAllowedChars) !=
- absl::string_view::npos) {
+ if (value.size() != 3 || !IsValidStatus(value)) {
QUICHE_VLOG(2) << "malformed status value: [" << absl::CEscape(value)
<< "]";
return HEADER_FIELD_INVALID;