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+
148169/*
149170 * Headers
150171 */
@@ -2915,7 +2936,8 @@ inline std::string decode_url(const std::string &s,
29152936
29162937inline std::string file_extension (const std::string &path) {
29172938 std::smatch m;
2918- static auto re = std::regex (" \\ .([a-zA-Z0-9]+)$" );
2939+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL (const std::regex, re,
2940+ (" \\ .([a-zA-Z0-9]+)$" ));
29192941 if (std::regex_search (path, m, re)) { return m[1 ].str (); }
29202942 return std::string ();
29212943}
@@ -4901,9 +4923,10 @@ class MultipartFormDataParser {
49014923 file_.content_type =
49024924 trim_copy (header.substr (header_content_type.size ()));
49034925 } else {
4904- static const std::regex re_content_disposition (
4905- R"~( ^Content-Disposition:\s*form-data;\s*(.*)$)~" ,
4906- std::regex_constants::icase);
4926+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL (
4927+ const std::regex, re_content_disposition,
4928+ (R"~( ^Content-Disposition:\s*form-data;\s*(.*)$)~" ,
4929+ std::regex_constants::icase));
49074930
49084931 std::smatch m;
49094932 if (std::regex_match (header, m, re_content_disposition)) {
@@ -4924,8 +4947,9 @@ class MultipartFormDataParser {
49244947 it = params.find (" filename*" );
49254948 if (it != params.end ()) {
49264949 // Only allow UTF-8 encoding...
4927- static const std::regex re_rfc5987_encoding (
4928- R"~( ^UTF-8''(.+?)$)~" , std::regex_constants::icase);
4950+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL (
4951+ const std::regex, re_rfc5987_encoding,
4952+ (R"~( ^UTF-8''(.+?)$)~" , std::regex_constants::icase));
49294953
49304954 std::smatch m2;
49314955 if (std::regex_match (it->second , m2, re_rfc5987_encoding)) {
@@ -5092,13 +5116,13 @@ inline std::string random_string(size_t length) {
50925116 // std::random_device might actually be deterministic on some
50935117 // platforms, but due to lack of support in the c++ standard library,
50945118 // 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 );
5119+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL ( std::mt19937, engine, ([]() {
5120+ std::random_device seed_gen;
5121+ std::seed_seq seed_sequence{
5122+ seed_gen (), seed_gen (),
5123+ seed_gen (), seed_gen ()};
5124+ return std::mt19937 (seed_sequence);
5125+ }()) );
51025126
51035127 std::string result;
51045128 for (size_t i = 0 ; i < length; i++) {
@@ -5612,7 +5636,8 @@ inline bool parse_www_authenticate(const Response &res,
56125636 bool is_proxy) {
56135637 auto auth_key = is_proxy ? " Proxy-Authenticate" : " WWW-Authenticate" ;
56145638 if (res.has_header (auth_key)) {
5615- static auto re = std::regex (R"~( (?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~" );
5639+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL (
5640+ const std::regex, re, (R"~( (?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~" ));
56165641 auto s = res.get_header_value (auth_key);
56175642 auto pos = s.find (' ' );
56185643 if (pos != std::string::npos) {
@@ -5696,7 +5721,7 @@ inline void hosted_at(const std::string &hostname,
56965721inline std::string append_query_params (const std::string &path,
56975722 const Params ¶ms) {
56985723 std::string path_with_query = path;
5699- const static std::regex re (" [^?]+\\ ?.*" );
5724+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL ( const std::regex, re, (" [^?]+\\ ?.*" ) );
57005725 auto delm = std::regex_match (path, re) ? ' &' : ' ?' ;
57015726 path_with_query += delm + detail::params_to_query_str (params);
57025727 return path_with_query;
@@ -5916,7 +5941,7 @@ Result::get_request_header_value_count(const std::string &key) const {
59165941
59175942// Stream implementation
59185943inline ssize_t Stream::write (const char *ptr) {
5919- return write (ptr, strlen (ptr));
5944+ return write (ptr, std:: strlen (ptr));
59205945}
59215946
59225947inline ssize_t Stream::write (const std::string &s) {
@@ -6470,9 +6495,9 @@ inline bool Server::parse_request_line(const char *s, Request &req) const {
64706495 if (count != 3 ) { return false ; }
64716496 }
64726497
6473- static const std::set<std::string> methods{
6474- " GET " , " HEAD" , " POST" , " PUT" , " DELETE" ,
6475- " CONNECT " , " OPTIONS" , " TRACE" , " PATCH" , " PRI" };
6498+ CPPHTTPLIB_DEFINE_STATIC ( std::set<std::string>, methods,
6499+ ({ " GET " , " HEAD" , " POST" , " PUT" , " DELETE" , " CONNECT " ,
6500+ " OPTIONS" , " TRACE" , " PATCH" , " PRI" })) ;
64766501
64776502 if (methods.find (req.method ) == methods.end ()) { return false ; }
64786503
@@ -7459,9 +7484,11 @@ inline bool ClientImpl::read_response_line(Stream &strm, const Request &req,
74597484 if (!line_reader.getline ()) { return false ; }
74607485
74617486#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
7462- const static std::regex re (" (HTTP/1\\ .[01]) (\\ d{3})(?: (.*?))?\r ?\n " );
7487+ CPPTHTTPLIB_DEFINE_LOCAL_THREAD_LOCALSTATIC (
7488+ std::regex, re, (" (HTTP/1\\ .[01]) (\\ d{3})(?: (.*?))?\r ?\n " ));
74637489#else
7464- const static std::regex re (" (HTTP/1\\ .[01]) (\\ d{3})(?: (.*?))?\r\n " );
7490+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL (
7491+ const std::regex, re, (" (HTTP/1\\ .[01]) (\\ d{3})(?: (.*?))?\r\n " ));
74657492#endif
74667493
74677494 std::cmatch m;
@@ -7693,8 +7720,9 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
76937720 auto location = res.get_header_value (" location" );
76947721 if (location.empty ()) { return false ; }
76957722
7696- const static std::regex re (
7697- R"( (?:(https?):)?(?://(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)" );
7723+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL (
7724+ const std::regex, re,
7725+ (R"( (?:(https?):)?(?://(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)" ));
76987726
76997727 std::smatch m;
77007728 if (!std::regex_match (location, m, re)) { return false ; }
@@ -9787,8 +9815,10 @@ inline Client::Client(const std::string &scheme_host_port)
97879815inline Client::Client (const std::string &scheme_host_port,
97889816 const std::string &client_cert_path,
97899817 const std::string &client_key_path) {
9790- const static std::regex re (
9791- R"( (?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)" );
9818+
9819+ CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL (
9820+ const std::regex, re,
9821+ (R"( (?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)" ));
97929822
97939823 std::smatch m;
97949824 if (std::regex_match (scheme_host_port, m, re)) {
0 commit comments