Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 17 additions & 33 deletions runtime/fastly/common/normalize_http_method.cpp
Original file line number Diff line number Diff line change
@@ -1,44 +1,28 @@
#include <algorithm>
#include <cctype>
#include <string_view>

using namespace std::literals::string_view_literals;

namespace fastly::common {
namespace {
inline char *ascii_uppercase(char *str, size_t length) {
char *up = reinterpret_cast<char *>(malloc(length + 1));
int i = 0;
while (i < length) {
auto ch = str[i];
if (ch >= 'a' && ch <= 'z') {
up[i] = ch & ~0x20;
} else {
up[i] = ch;
}
i++;
}
up[i] = '\0';
return up;
}
} // namespace

// https://fetch.spec.whatwg.org/#concept-method-normalize
// To normalize a method, if it is a byte-case-insensitive match for `DELETE`, `GET`, `HEAD`,
// `OPTIONS`, `POST`, or `PUT`, byte-uppercase it.
bool normalize_http_method(char *method, size_t length) {
auto m = std::string_view(method, length);
// It's quite likely the method is already uppercased,
// so let's check it first before we create a copy of the method to uppercase it.
// These have been order by most likely to occur.
if (m != "GET"sv && m != "HEAD"sv && m != "OPTIONS"sv && m != "POST"sv && m != "PUT"sv &&
m != "DELETE"sv) [[unlikely]] {
auto umethod = ascii_uppercase(method, length);
if (strcmp(umethod, "GET") == 0 || strcmp(umethod, "HEAD") == 0 ||
strcmp(umethod, "OPTIONS") == 0 || strcmp(umethod, "POST") == 0 ||
strcmp(umethod, "PUT") == 0 || strcmp(umethod, "DELETE") == 0) {
strcpy(method, umethod);
return true;
}
// Ordered by most likely to occur.
constexpr std::string_view methods[] = {"GET", "HEAD", "OPTIONS", "POST", "PUT", "DELETE"};
std::string_view m(method, length);

auto iequal = [](unsigned char a, unsigned char b) { return std::toupper(a) == std::toupper(b); };

auto it = std::ranges::find_if(methods, [&](std::string_view candidate) {
return std::ranges::equal(m, candidate, iequal);
});

if (it == std::ranges::end(methods) || *it == m) {
return false; // not a recognized method, or already normalized
}
return false;

std::ranges::copy(*it, method); // copy the already-uppercase canonical form
return true;
}
} // namespace fastly::common
Loading