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+
158+ #ifndef CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL
159+ #ifdef CPPHTTPLIB_NO_EXIT_TIME_DESTRUCTORS
160+ #define CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL (var_type, var, init ) \
161+ static thread_local var_type &var = \
162+ *new typename std::remove_cv<var_type>::type init
163+ #else
164+ #define CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL (var_type, var, init ) \
165+ static thread_local var_type var = \
166+ typename std::remove_cv<var_type>::type init
167+ #endif
168+ #endif
169+
148170/*
149171 * Headers
150172 */
@@ -2915,7 +2937,8 @@ inline std::string decode_url(const std::string &s,
29152937
29162938inline std::string file_extension (const std::string &path) {
29172939 std::smatch m;
2918- static auto re = std::regex (" \\ .([a-zA-Z0-9]+)$" );
2940+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL (const std::regex, re,
2941+ (" \\ .([a-zA-Z0-9]+)$" ));
29192942 if (std::regex_search (path, m, re)) { return m[1 ].str (); }
29202943 return std::string ();
29212944}
@@ -4901,9 +4924,10 @@ class MultipartFormDataParser {
49014924 file_.content_type =
49024925 trim_copy (header.substr (header_content_type.size ()));
49034926 } else {
4904- static const std::regex re_content_disposition (
4905- R"~( ^Content-Disposition:\s*form-data;\s*(.*)$)~" ,
4906- std::regex_constants::icase);
4927+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL (
4928+ const std::regex, re_content_disposition,
4929+ (R"~( ^Content-Disposition:\s*form-data;\s*(.*)$)~" ,
4930+ std::regex_constants::icase));
49074931
49084932 std::smatch m;
49094933 if (std::regex_match (header, m, re_content_disposition)) {
@@ -4924,8 +4948,9 @@ class MultipartFormDataParser {
49244948 it = params.find (" filename*" );
49254949 if (it != params.end ()) {
49264950 // Only allow UTF-8 encoding...
4927- static const std::regex re_rfc5987_encoding (
4928- R"~( ^UTF-8''(.+?)$)~" , std::regex_constants::icase);
4951+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL (
4952+ const std::regex, re_rfc5987_encoding,
4953+ (R"~( ^UTF-8''(.+?)$)~" , std::regex_constants::icase));
49294954
49304955 std::smatch m2;
49314956 if (std::regex_match (it->second , m2, re_rfc5987_encoding)) {
@@ -5092,13 +5117,13 @@ inline std::string random_string(size_t length) {
50925117 // std::random_device might actually be deterministic on some
50935118 // platforms, but due to lack of support in the c++ standard library,
50945119 // doing better requires either some ugly hacks or breaking portability.
5095- static std::random_device seed_gen;
5096-
5097- // Request 128 bits of entropy for initialization
5098- static std::seed_seq seed_sequence{ seed_gen (), seed_gen (), seed_gen (),
5099- seed_gen ()};
5100-
5101- static std::mt19937 engine (seed_sequence );
5120+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL ( std::mt19937, engine, ([]() {
5121+ std::random_device seed_gen;
5122+ std::seed_seq seed_sequence{
5123+ seed_gen (), seed_gen (),
5124+ seed_gen (), seed_gen ()};
5125+ return std::mt19937 (seed_sequence);
5126+ }()) );
51025127
51035128 std::string result;
51045129 for (size_t i = 0 ; i < length; i++) {
@@ -5612,7 +5637,8 @@ inline bool parse_www_authenticate(const Response &res,
56125637 bool is_proxy) {
56135638 auto auth_key = is_proxy ? " Proxy-Authenticate" : " WWW-Authenticate" ;
56145639 if (res.has_header (auth_key)) {
5615- static auto re = std::regex (R"~( (?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~" );
5640+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL (
5641+ const std::regex, re, (R"~( (?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~" ));
56165642 auto s = res.get_header_value (auth_key);
56175643 auto pos = s.find (' ' );
56185644 if (pos != std::string::npos) {
@@ -5696,7 +5722,7 @@ inline void hosted_at(const std::string &hostname,
56965722inline std::string append_query_params (const std::string &path,
56975723 const Params ¶ms) {
56985724 std::string path_with_query = path;
5699- const static std::regex re (" [^?]+\\ ?.*" );
5725+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL ( const std::regex, re, (" [^?]+\\ ?.*" ) );
57005726 auto delm = std::regex_match (path, re) ? ' &' : ' ?' ;
57015727 path_with_query += delm + detail::params_to_query_str (params);
57025728 return path_with_query;
@@ -5916,7 +5942,7 @@ Result::get_request_header_value_count(const std::string &key) const {
59165942
59175943// Stream implementation
59185944inline ssize_t Stream::write (const char *ptr) {
5919- return write (ptr, strlen (ptr));
5945+ return write (ptr, std:: strlen (ptr));
59205946}
59215947
59225948inline ssize_t Stream::write (const std::string &s) {
@@ -6470,9 +6496,9 @@ inline bool Server::parse_request_line(const char *s, Request &req) const {
64706496 if (count != 3 ) { return false ; }
64716497 }
64726498
6473- static const std::set<std::string> methods{
6474- " GET " , " HEAD" , " POST" , " PUT" , " DELETE" ,
6475- " CONNECT " , " OPTIONS" , " TRACE" , " PATCH" , " PRI" };
6499+ CPPHTTPLIB_DEFINE_STATIC ( std::set<std::string>, methods,
6500+ ({ " GET " , " HEAD" , " POST" , " PUT" , " DELETE" , " CONNECT " ,
6501+ " OPTIONS" , " TRACE" , " PATCH" , " PRI" })) ;
64766502
64776503 if (methods.find (req.method ) == methods.end ()) { return false ; }
64786504
@@ -7459,9 +7485,11 @@ inline bool ClientImpl::read_response_line(Stream &strm, const Request &req,
74597485 if (!line_reader.getline ()) { return false ; }
74607486
74617487#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
7462- const static std::regex re (" (HTTP/1\\ .[01]) (\\ d{3})(?: (.*?))?\r ?\n " );
7488+ CPPTHTTPLIB_DEFINE_LOCAL_THREAD_LOCALSTATIC (
7489+ std::regex, re, (" (HTTP/1\\ .[01]) (\\ d{3})(?: (.*?))?\r ?\n " ));
74637490#else
7464- const static std::regex re (" (HTTP/1\\ .[01]) (\\ d{3})(?: (.*?))?\r\n " );
7491+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL (
7492+ const std::regex, re, (" (HTTP/1\\ .[01]) (\\ d{3})(?: (.*?))?\r\n " ));
74657493#endif
74667494
74677495 std::cmatch m;
@@ -7693,8 +7721,9 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
76937721 auto location = res.get_header_value (" location" );
76947722 if (location.empty ()) { return false ; }
76957723
7696- const static std::regex re (
7697- R"( (?:(https?):)?(?://(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)" );
7724+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL (
7725+ const std::regex, re,
7726+ (R"( (?:(https?):)?(?://(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)" ));
76987727
76997728 std::smatch m;
77007729 if (!std::regex_match (location, m, re)) { return false ; }
@@ -9787,8 +9816,10 @@ inline Client::Client(const std::string &scheme_host_port)
97879816inline Client::Client (const std::string &scheme_host_port,
97889817 const std::string &client_cert_path,
97899818 const std::string &client_key_path) {
9790- const static std::regex re (
9791- R"( (?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)" );
9819+
9820+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL (
9821+ const std::regex, re,
9822+ (R"( (?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)" ));
97929823
97939824 std::smatch m;
97949825 if (std::regex_match (scheme_host_port, m, re)) {
0 commit comments