Skip to content

Commit b6ec06b

Browse files
Add macro for static variable definition
Introduce macro CPPHTTPLIB_DEFINE_STATIC to define static variables, with optional dynamic allocation to avoid exit-time destructors and race conditions with atexit handlers.
1 parent 4409a68 commit b6ec06b

File tree

2 files changed

+42
-22
lines changed

2 files changed

+42
-22
lines changed

httplib.h

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,16 @@
145145
#define CPPHTTPLIB_LISTEN_BACKLOG 5
146146
#endif
147147

148+
#ifndef CPPHTTPLIB_DEFINE_STATIC
149+
#ifdef CPPHTTPLIB_NO_EXIT_TIME_DESTRUCTORS
150+
#define CPPHTTPLIB_DEFINE_STATIC(var_type, var, init) \
151+
static var_type &var = *new typename std::remove_cv<var_type>::type init
152+
#else
153+
#define CPPHTTPLIB_DEFINE_STATIC(var_type, var, init) \
154+
static var_type var = typename std::remove_cv<var_type>::type init
155+
#endif
156+
#endif
157+
148158
/*
149159
* Headers
150160
*/
@@ -2919,7 +2929,7 @@ inline std::string decode_url(const std::string &s,
29192929

29202930
inline std::string file_extension(const std::string &path) {
29212931
std::smatch m;
2922-
static auto re = std::regex("\\.([a-zA-Z0-9]+)$");
2932+
CPPHTTPLIB_DEFINE_STATIC(const std::regex, re, ("\\.([a-zA-Z0-9]+)$"));
29232933
if (std::regex_search(path, m, re)) { return m[1].str(); }
29242934
return std::string();
29252935
}
@@ -4912,9 +4922,10 @@ class MultipartFormDataParser {
49124922
file_.content_type =
49134923
trim_copy(header.substr(str_len(header_content_type)));
49144924
} else {
4915-
static const std::regex re_content_disposition(
4916-
R"~(^Content-Disposition:\s*form-data;\s*(.*)$)~",
4917-
std::regex_constants::icase);
4925+
CPPHTTPLIB_DEFINE_STATIC(
4926+
const std::regex, re_content_disposition,
4927+
(R"~(^Content-Disposition:\s*form-data;\s*(.*)$)~",
4928+
std::regex_constants::icase));
49184929

49194930
std::smatch m;
49204931
if (std::regex_match(header, m, re_content_disposition)) {
@@ -4935,8 +4946,9 @@ class MultipartFormDataParser {
49354946
it = params.find("filename*");
49364947
if (it != params.end()) {
49374948
// Only allow UTF-8 encoding...
4938-
static const std::regex re_rfc5987_encoding(
4939-
R"~(^UTF-8''(.+?)$)~", std::regex_constants::icase);
4949+
CPPHTTPLIB_DEFINE_STATIC(
4950+
const std::regex, re_rfc5987_encoding,
4951+
(R"~(^UTF-8''(.+?)$)~", std::regex_constants::icase));
49404952

49414953
std::smatch m2;
49424954
if (std::regex_match(it->second, m2, re_rfc5987_encoding)) {
@@ -5614,15 +5626,16 @@ class WSInit {
56145626
bool is_valid_ = false;
56155627
};
56165628

5617-
static WSInit wsinit_;
5629+
CPPHTTPLIB_DEFINE_STATIC(WSInit, wsinit_, ());
56185630
#endif
56195631

56205632
inline bool parse_www_authenticate(const Response &res,
56215633
std::map<std::string, std::string> &auth,
56225634
bool is_proxy) {
56235635
auto auth_key = is_proxy ? "Proxy-Authenticate" : "WWW-Authenticate";
56245636
if (res.has_header(auth_key)) {
5625-
static auto re = std::regex(R"~((?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~");
5637+
CPPHTTPLIB_DEFINE_STATIC(const std::regex, re,
5638+
(R"~((?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~"));
56265639
auto s = res.get_header_value(auth_key);
56275640
auto pos = s.find(' ');
56285641
if (pos != std::string::npos) {
@@ -5706,7 +5719,7 @@ inline void hosted_at(const std::string &hostname,
57065719
inline std::string append_query_params(const std::string &path,
57075720
const Params &params) {
57085721
std::string path_with_query = path;
5709-
const static std::regex re("[^?]+\\?.*");
5722+
CPPHTTPLIB_DEFINE_STATIC(const std::regex, re, ("[^?]+\\?.*"));
57105723
auto delm = std::regex_match(path, re) ? '&' : '?';
57115724
path_with_query += delm + detail::params_to_query_str(params);
57125725
return path_with_query;
@@ -6480,9 +6493,9 @@ inline bool Server::parse_request_line(const char *s, Request &req) const {
64806493
if (count != 3) { return false; }
64816494
}
64826495

6483-
static const std::set<std::string> methods{
6484-
"GET", "HEAD", "POST", "PUT", "DELETE",
6485-
"CONNECT", "OPTIONS", "TRACE", "PATCH", "PRI"};
6496+
CPPHTTPLIB_DEFINE_STATIC(std::set<std::string>, methods,
6497+
({"GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT",
6498+
"OPTIONS", "TRACE", "PATCH", "PRI"}));
64866499

64876500
if (methods.find(req.method) == methods.end()) { return false; }
64886501

@@ -7469,9 +7482,11 @@ inline bool ClientImpl::read_response_line(Stream &strm, const Request &req,
74697482
if (!line_reader.getline()) { return false; }
74707483

74717484
#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
7472-
const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n");
7485+
CPPTHTTPLIB_DEFINE_STATIC(std::regex, re,
7486+
("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n"));
74737487
#else
7474-
const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n");
7488+
CPPHTTPLIB_DEFINE_STATIC(const std::regex, re,
7489+
("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n"));
74757490
#endif
74767491

74777492
std::cmatch m;
@@ -7703,8 +7718,9 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
77037718
auto location = res.get_header_value("location");
77047719
if (location.empty()) { return false; }
77057720

7706-
const static std::regex re(
7707-
R"((?:(https?):)?(?://(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)");
7721+
CPPHTTPLIB_DEFINE_STATIC(
7722+
const std::regex, re,
7723+
(R"((?:(https?):)?(?://(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)"));
77087724

77097725
std::smatch m;
77107726
if (!std::regex_match(location, m, re)) { return false; }
@@ -9787,8 +9803,10 @@ inline Client::Client(const std::string &scheme_host_port)
97879803
inline Client::Client(const std::string &scheme_host_port,
97889804
const std::string &client_cert_path,
97899805
const std::string &client_key_path) {
9790-
const static std::regex re(
9791-
R"((?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)");
9806+
9807+
CPPHTTPLIB_DEFINE_STATIC(
9808+
const std::regex, re,
9809+
(R"((?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)"));
97929810

97939811
std::smatch m;
97949812
if (std::regex_match(scheme_host_port, m, re)) {

test/test.cc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,14 @@ using namespace httplib;
4040
const char *HOST = "localhost";
4141
const int PORT = 1234;
4242

43-
const string LONG_QUERY_VALUE = string(25000, '@');
44-
const string LONG_QUERY_URL = "/long-query-value?key=" + LONG_QUERY_VALUE;
43+
CPPHTTPLIB_DEFINE_STATIC(const string, LONG_QUERY_VALUE, (25000, '@'));
44+
CPPHTTPLIB_DEFINE_STATIC(const string, LONG_QUERY_URL,
45+
("/long-query-value?key=" + LONG_QUERY_VALUE));
4546

46-
const std::string JSON_DATA = "{\"hello\":\"world\"}";
47+
CPPHTTPLIB_DEFINE_STATIC(const string, JSON_DATA, ("{\"hello\":\"world\"}"));
4748

48-
const string LARGE_DATA = string(1024 * 1024 * 100, '@'); // 100MB
49+
CPPHTTPLIB_DEFINE_STATIC(const string, LARGE_DATA,
50+
(1024 * 1024 * 100, '@')); // 100MB
4951

5052
MultipartFormData &get_file_value(MultipartFormDataItems &files,
5153
const char *key) {

0 commit comments

Comments
 (0)