зеркало из https://github.com/microsoft/CCF.git
76 строки
2.0 KiB
C++
76 строки
2.0 KiB
C++
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the Apache 2.0 License.
|
|
#pragma once
|
|
|
|
#define FMT_HEADER_ONLY
|
|
#include <regex>
|
|
#include <set>
|
|
#include <string>
|
|
|
|
namespace ccf
|
|
{
|
|
namespace http
|
|
{
|
|
/** Utility class to resolve If-Match and If-None-Match as described
|
|
* in https://www.rfc-editor.org/rfc/rfc9110#field.if-match
|
|
*/
|
|
class Matcher
|
|
{
|
|
private:
|
|
/// If-Match header is present and has the value "*"
|
|
bool any_value = false;
|
|
/// If-Match header is present and has specific etag values
|
|
std::set<std::string> if_etags;
|
|
|
|
public:
|
|
/** Construct a Matcher from a match header
|
|
*
|
|
* Note: Weak tags are not supported.
|
|
*/
|
|
Matcher(const std::string& match_header)
|
|
{
|
|
if (match_header == "*")
|
|
{
|
|
any_value = true;
|
|
return;
|
|
}
|
|
|
|
std::regex etag_rx("\\\"([0-9a-f]+)\\\",?\\s*");
|
|
auto etags_begin = std::sregex_iterator(
|
|
match_header.begin(), match_header.end(), etag_rx);
|
|
auto etags_end = std::sregex_iterator();
|
|
ssize_t last_matched = 0;
|
|
|
|
for (std::sregex_iterator i = etags_begin; i != etags_end; ++i)
|
|
{
|
|
if (i->position() != last_matched)
|
|
{
|
|
throw std::runtime_error("Invalid If-Match header");
|
|
}
|
|
std::smatch match = *i;
|
|
if_etags.insert(match[1].str());
|
|
last_matched = match.position() + match.length();
|
|
}
|
|
|
|
ssize_t last_index_in_header = match_header.size();
|
|
|
|
if (last_matched != last_index_in_header || if_etags.empty())
|
|
{
|
|
throw std::runtime_error("Invalid If-Match header");
|
|
}
|
|
}
|
|
|
|
/// Check if a given ETag matches the If-Match/If-None-Match header
|
|
bool matches(const std::string& etag) const
|
|
{
|
|
return any_value || if_etags.contains(etag);
|
|
}
|
|
|
|
/// Check if the header will match any ETag (*)
|
|
bool is_any() const
|
|
{
|
|
return any_value;
|
|
}
|
|
};
|
|
}
|
|
} |