From fac61858bc7360982de6fa6795a89ef1496ef972 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 1 Aug 2018 16:15:33 -0700 Subject: [PATCH] Unify handling of tolower operations to avoid locale sensitivity. --- Release/include/cpprest/asyncrt_utils.h | 83 ++++++++--------- Release/include/cpprest/http_headers.h | 40 ++++----- .../BlackJack_Client/BlackJackClient.cpp | 38 ++++---- Release/src/http/common/http_msg.cpp | 73 ++++++++------- Release/src/http/oauth/oauth2.cpp | 6 +- Release/src/uri/uri.cpp | 21 +---- Release/src/utilities/asyncrt_utils.cpp | 89 ++++++++++++++++++- .../src/websockets/client/ws_client_winrt.cpp | 6 +- .../src/websockets/client/ws_client_wspp.cpp | 3 +- 9 files changed, 210 insertions(+), 149 deletions(-) diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index 68aa738be0..5600888fea 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -28,7 +28,6 @@ #ifndef _WIN32 #include -#include #if !defined(ANDROID) && !defined(__ANDROID__) && defined(HAVE_XLOCALE_H) // CodePlex 269 /* Systems using glibc: xlocale.h has been removed from glibc 2.26 The above include of locale.h is sufficient @@ -393,19 +392,48 @@ namespace details } /// - /// Cross platform utility function for performing case insensitive string comparision. + /// Cross platform utility function for performing case insensitive string equality comparision. /// /// First string to compare. /// Second strong to compare. /// true if the strings are equivalent, false otherwise - inline bool str_icmp(const utility::string_t &left, const utility::string_t &right) - { -#ifdef _WIN32 - return _wcsicmp(left.c_str(), right.c_str()) == 0; -#else - return boost::iequals(left, right); -#endif - } + _ASYNCRTIMP bool __cdecl str_iequal(const std::string &left, const std::string &right) CPPREST_NOEXCEPT; + + /// + /// Cross platform utility function for performing case insensitive string equality comparision. + /// + /// First string to compare. + /// Second strong to compare. + /// true if the strings are equivalent, false otherwise + _ASYNCRTIMP bool __cdecl str_iequal(const std::wstring &left, const std::wstring &right) CPPREST_NOEXCEPT; + + /// + /// Cross platform utility function for performing case insensitive string less-than comparision. + /// + /// First string to compare. + /// Second strong to compare. + /// true if a lowercase view of left is lexicographically less than a lowercase view of right; otherwise, false. + _ASYNCRTIMP bool __cdecl str_iless(const std::string &left, const std::string &right) CPPREST_NOEXCEPT; + + /// + /// Cross platform utility function for performing case insensitive string less-than comparision. + /// + /// First string to compare. + /// Second strong to compare. + /// true if a lowercase view of left is lexicographically less than a lowercase view of right; otherwise, false. + _ASYNCRTIMP bool __cdecl str_iless(const std::wstring &left, const std::wstring &right) CPPREST_NOEXCEPT; + + /// + /// Convert a string to lowercase in place. + /// + /// The string to convert to lowercase. + _ASYNCRTIMP void __cdecl inplace_tolower(std::string &target) CPPREST_NOEXCEPT; + + /// + /// Convert a string to lowercase in place. + /// + /// The string to convert to lowercase. + _ASYNCRTIMP void __cdecl inplace_tolower(std::wstring &target) CPPREST_NOEXCEPT; #ifdef _WIN32 @@ -607,41 +635,6 @@ class datetime interval_type m_interval; }; -#ifndef _WIN32 - -// temporary workaround for the fact that -// utf16char is not fully supported in GCC -class cmp -{ -public: - - static int icmp(std::string left, std::string right) - { - size_t i; - for (i = 0; i < left.size(); ++i) - { - if (i == right.size()) return 1; - - auto l = cmp::tolower(left[i]); - auto r = cmp::tolower(right[i]); - if (l > r) return 1; - if (l < r) return -1; - } - if (i < right.size()) return -1; - return 0; - } - -private: - static char tolower(char c) - { - if (c >= 'A' && c <= 'Z') - return static_cast(c - 'A' + 'a'); - return c; - } -}; - -#endif - inline int operator- (datetime t1, datetime t2) { auto diff = (t1.m_interval - t2.m_interval); diff --git a/Release/include/cpprest/http_headers.h b/Release/include/cpprest/http_headers.h index 2458872410..f5bee96535 100644 --- a/Release/include/cpprest/http_headers.h +++ b/Release/include/cpprest/http_headers.h @@ -68,30 +68,30 @@ class http_headers { bool operator()(const utility::string_t &str1, const utility::string_t &str2) const { -#ifdef _WIN32 - return _wcsicmp(str1.c_str(), str2.c_str()) < 0; -#else - return utility::cmp::icmp(str1, str2) < 0; -#endif + return utility::details::str_iless(str1, str2); } }; +private: + typedef std::map inner_container; +public: + /// /// STL-style typedefs /// - typedef std::map::key_type key_type; - typedef std::map::key_compare key_compare; - typedef std::map::allocator_type allocator_type; - typedef std::map::size_type size_type; - typedef std::map::difference_type difference_type; - typedef std::map::pointer pointer; - typedef std::map::const_pointer const_pointer; - typedef std::map::reference reference; - typedef std::map::const_reference const_reference; - typedef std::map::iterator iterator; - typedef std::map::const_iterator const_iterator; - typedef std::map::reverse_iterator reverse_iterator; - typedef std::map::const_reverse_iterator const_reverse_iterator; + typedef typename inner_container::key_type key_type; + typedef typename inner_container::key_compare key_compare; + typedef typename inner_container::allocator_type allocator_type; + typedef typename inner_container::size_type size_type; + typedef typename inner_container::difference_type difference_type; + typedef typename inner_container::pointer pointer; + typedef typename inner_container::const_pointer const_pointer; + typedef typename inner_container::reference reference; + typedef typename inner_container::const_reference const_reference; + typedef typename inner_container::iterator iterator; + typedef typename inner_container::const_iterator const_iterator; + typedef typename inner_container::reverse_iterator reverse_iterator; + typedef typename inner_container::const_reverse_iterator const_reverse_iterator; /// /// Constructs an empty set of HTTP headers. @@ -318,7 +318,7 @@ class http_headers } // Headers are stored in a map with case insensitive key. - std::map m_headers; + inner_container m_headers; }; -}} \ No newline at end of file +}} diff --git a/Release/samples/BlackJack/BlackJack_Client/BlackJackClient.cpp b/Release/samples/BlackJack/BlackJack_Client/BlackJackClient.cpp index 0e84d14d69..1ca303fbdc 100644 --- a/Release/samples/BlackJack/BlackJack_Client/BlackJackClient.cpp +++ b/Release/samples/BlackJack/BlackJack_Client/BlackJackClient.cpp @@ -13,17 +13,12 @@ #include #include #include +#include #include #include "../BlackJack_Server/messagetypes.h" -#ifdef _WIN32 -# define iequals(x, y) (_stricmp((x), (y))==0) -#else -# define iequals(x, y) boost::iequals((x), (y)) -#endif - using namespace std; -using namespace web; +using namespace web; using namespace utility; using namespace http; using namespace http::client; @@ -134,7 +129,7 @@ void PrintTable(const http_response &response, bool &refresh) } } -// +// // Entry point for the blackjack client. // Arguments: BlackJack_Client.exe // If port is not specified, client will assume that the server is listening on port 34568 @@ -179,7 +174,11 @@ int main(int argc, char *argv[]) ucout << "Enter method:"; cin >> method; - if ( iequals(method.c_str(), "quit") ) + const auto methodFirst = &method[0]; + const auto methodLast = methodFirst + method.size(); + std::use_facet>(std::locale::classic()).tolower(methodFirst, methodLast); + + if (method == "quit") { if ( !userName.empty() && !table.empty() ) { @@ -190,12 +189,12 @@ int main(int argc, char *argv[]) break; } - if ( iequals(method.c_str(), "name") ) + if (method == "name") { ucout << "Enter user name:"; ucin >> userName; } - else if ( iequals(method.c_str(), "join") ) + else if (method == "join") { ucout << "Enter table name:"; ucin >> table; @@ -206,16 +205,16 @@ int main(int argc, char *argv[]) buf << table << U("?name=") << userName; CheckResponse("blackjack/dealer", bjDealer.request(methods::POST, buf.str()).get(), was_refresh); } - else if ( iequals(method.c_str(), "hit") - || iequals(method.c_str(), "stay") - || iequals(method.c_str(), "double") ) + else if (method == "hit" + || method == "stay" + || method == "double") { utility::ostringstream_t buf; buf << table << U("?request=") << utility::conversions::to_string_t(method) << U("&name=") << userName; PrintTable(CheckResponse("blackjack/dealer", bjDealer.request(methods::PUT, buf.str()).get()), was_refresh); } - else if ( iequals(method.c_str(), "bet") - || iequals(method.c_str(), "insure") ) + else if (method == "bet" + ||method == "insure") { utility::string_t bet; ucout << "Enter bet:"; @@ -227,11 +226,11 @@ int main(int argc, char *argv[]) buf << table << U("?request=") << utility::conversions::to_string_t(method) << U("&name=") << userName << U("&amount=") << bet; PrintTable(CheckResponse("blackjack/dealer", bjDealer.request(methods::PUT, buf.str()).get()), was_refresh); } - else if ( iequals(method.c_str(), "newtbl") ) + else if (method == "newtbl") { CheckResponse("blackjack/dealer", bjDealer.request(methods::POST).get(), was_refresh); } - else if ( iequals(method.c_str(), "leave") ) + else if (method == "leave") { ucout << "Enter table:"; ucin >> table; @@ -242,7 +241,7 @@ int main(int argc, char *argv[]) buf << table << U("?name=") << userName; CheckResponse("blackjack/dealer", bjDealer.request(methods::DEL, buf.str()).get(), was_refresh); } - else if ( iequals(method.c_str(), "list") ) + else if (method == "list") { was_refresh = false; http_response response = CheckResponse("blackjack/dealer", bjDealer.request(methods::GET).get()); @@ -268,4 +267,3 @@ int main(int argc, char *argv[]) return 0; } - diff --git a/Release/src/http/common/http_msg.cpp b/Release/src/http/common/http_msg.cpp index ad2c70e9d7..ece2d08c1e 100644 --- a/Release/src/http/common/http_msg.cpp +++ b/Release/src/http/common/http_msg.cpp @@ -422,7 +422,7 @@ static bool is_content_type_one_of(const utility::string_t *first, const utility { while (first != last) { - if (utility::details::str_icmp(*first, value)) + if (utility::details::str_iequal(*first, value)) { return true; } @@ -460,7 +460,7 @@ static bool is_content_type_textual(const utility::string_t &content_type) }; #endif - if (content_type.size() >= 4 && utility::details::str_icmp(content_type.substr(0, 4), _XPLATSTR("text"))) + if (content_type.size() >= 4 && utility::details::str_iequal(content_type.substr(0, 4), _XPLATSTR("text"))) { return true; } @@ -554,7 +554,7 @@ static void parse_content_type_and_charset(const utility::string_t &content_type // Split and make sure 'charset' utility::string_t charset_key = possible_charset.substr(0, equals_index); trim_whitespace(charset_key); - if (!utility::details::str_icmp(charset_key, _XPLATSTR("charset"))) + if (!utility::details::str_iequal(charset_key, _XPLATSTR("charset"))) { charset = get_default_charset(content); return; @@ -609,9 +609,9 @@ utf8string details::http_msg_base::extract_utf8string(bool ignore_content_type) auto buf_r = instream().streambuf(); // Perform the correct character set conversion if one is necessary. - if (utility::details::str_icmp(charset, charset_types::utf8) - || utility::details::str_icmp(charset, charset_types::usascii) - || utility::details::str_icmp(charset, charset_types::ascii)) + if (utility::details::str_iequal(charset, charset_types::utf8) + || utility::details::str_iequal(charset, charset_types::usascii) + || utility::details::str_iequal(charset, charset_types::ascii)) { std::string body; body.resize((std::string::size_type)buf_r.in_avail()); @@ -620,7 +620,7 @@ utf8string details::http_msg_base::extract_utf8string(bool ignore_content_type) } // Latin1 - else if (utility::details::str_icmp(charset, charset_types::latin1)) + else if (utility::details::str_iequal(charset, charset_types::latin1)) { std::string body; body.resize((std::string::size_type)buf_r.in_avail()); @@ -629,7 +629,7 @@ utf8string details::http_msg_base::extract_utf8string(bool ignore_content_type) } // utf-16 - else if (utility::details::str_icmp(charset, charset_types::utf16)) + else if (utility::details::str_iequal(charset, charset_types::utf16)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); @@ -638,7 +638,7 @@ utf8string details::http_msg_base::extract_utf8string(bool ignore_content_type) } // utf-16le - else if (utility::details::str_icmp(charset, charset_types::utf16le)) + else if (utility::details::str_iequal(charset, charset_types::utf16le)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); @@ -647,7 +647,7 @@ utf8string details::http_msg_base::extract_utf8string(bool ignore_content_type) } // utf-16be - else if (utility::details::str_icmp(charset, charset_types::utf16be)) + else if (utility::details::str_iequal(charset, charset_types::utf16be)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); @@ -671,7 +671,7 @@ utf16string details::http_msg_base::extract_utf16string(bool ignore_content_type auto buf_r = instream().streambuf(); // Perform the correct character set conversion if one is necessary. - if (utility::details::str_icmp(charset, charset_types::utf16le)) + if (utility::details::str_iequal(charset, charset_types::utf16le)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); @@ -680,9 +680,9 @@ utf16string details::http_msg_base::extract_utf16string(bool ignore_content_type } // utf-8, ascii - else if (utility::details::str_icmp(charset, charset_types::utf8) - || utility::details::str_icmp(charset, charset_types::usascii) - || utility::details::str_icmp(charset, charset_types::ascii)) + else if (utility::details::str_iequal(charset, charset_types::utf8) + || utility::details::str_iequal(charset, charset_types::usascii) + || utility::details::str_iequal(charset, charset_types::ascii)) { std::string body; body.resize((std::string::size_type)buf_r.in_avail()); @@ -691,7 +691,7 @@ utf16string details::http_msg_base::extract_utf16string(bool ignore_content_type } // Latin1 - else if (utility::details::str_icmp(charset, charset_types::latin1)) + else if (utility::details::str_iequal(charset, charset_types::latin1)) { std::string body; body.resize((std::string::size_type)buf_r.in_avail()); @@ -700,7 +700,7 @@ utf16string details::http_msg_base::extract_utf16string(bool ignore_content_type } // utf-16 - else if (utility::details::str_icmp(charset, charset_types::utf16)) + else if (utility::details::str_iequal(charset, charset_types::utf16)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); @@ -709,7 +709,7 @@ utf16string details::http_msg_base::extract_utf16string(bool ignore_content_type } // utf-16be - else if (utility::details::str_icmp(charset, charset_types::utf16be)) + else if (utility::details::str_iequal(charset, charset_types::utf16be)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); @@ -733,8 +733,8 @@ utility::string_t details::http_msg_base::extract_string(bool ignore_content_typ auto buf_r = instream().streambuf(); // Perform the correct character set conversion if one is necessary. - if (utility::details::str_icmp(charset, charset_types::usascii) - || utility::details::str_icmp(charset, charset_types::ascii)) + if (utility::details::str_iequal(charset, charset_types::usascii) + || utility::details::str_iequal(charset, charset_types::ascii)) { std::string body; body.resize((std::string::size_type)buf_r.in_avail()); @@ -743,7 +743,7 @@ utility::string_t details::http_msg_base::extract_string(bool ignore_content_typ } // Latin1 - if(utility::details::str_icmp(charset, charset_types::latin1)) + if(utility::details::str_iequal(charset, charset_types::latin1)) { std::string body; body.resize((std::string::size_type)buf_r.in_avail()); @@ -753,7 +753,7 @@ utility::string_t details::http_msg_base::extract_string(bool ignore_content_typ } // utf-8. - else if(utility::details::str_icmp(charset, charset_types::utf8)) + else if(utility::details::str_iequal(charset, charset_types::utf8)) { std::string body; body.resize((std::string::size_type)buf_r.in_avail()); @@ -762,7 +762,7 @@ utility::string_t details::http_msg_base::extract_string(bool ignore_content_typ } // utf-16. - else if(utility::details::str_icmp(charset, charset_types::utf16)) + else if(utility::details::str_iequal(charset, charset_types::utf16)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); @@ -771,7 +771,7 @@ utility::string_t details::http_msg_base::extract_string(bool ignore_content_typ } // utf-16le - else if(utility::details::str_icmp(charset, charset_types::utf16le)) + else if(utility::details::str_iequal(charset, charset_types::utf16le)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); @@ -780,7 +780,7 @@ utility::string_t details::http_msg_base::extract_string(bool ignore_content_typ } // utf-16be - else if(utility::details::str_icmp(charset, charset_types::utf16be)) + else if(utility::details::str_iequal(charset, charset_types::utf16be)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); @@ -804,7 +804,7 @@ json::value details::http_msg_base::_extract_json(bool ignore_content_type) auto buf_r = instream().streambuf(); // Latin1 - if(utility::details::str_icmp(charset, charset_types::latin1)) + if(utility::details::str_iequal(charset, charset_types::latin1)) { std::string body; body.resize(buf_r.in_avail()); @@ -814,9 +814,9 @@ json::value details::http_msg_base::_extract_json(bool ignore_content_type) } // utf-8, usascii and ascii - else if(utility::details::str_icmp(charset, charset_types::utf8) - || utility::details::str_icmp(charset, charset_types::usascii) - || utility::details::str_icmp(charset, charset_types::ascii)) + else if(utility::details::str_iequal(charset, charset_types::utf8) + || utility::details::str_iequal(charset, charset_types::usascii) + || utility::details::str_iequal(charset, charset_types::ascii)) { std::string body; body.resize(buf_r.in_avail()); @@ -825,7 +825,7 @@ json::value details::http_msg_base::_extract_json(bool ignore_content_type) } // utf-16. - else if(utility::details::str_icmp(charset, charset_types::utf16)) + else if(utility::details::str_iequal(charset, charset_types::utf16)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); @@ -834,7 +834,7 @@ json::value details::http_msg_base::_extract_json(bool ignore_content_type) } // utf-16le - else if(utility::details::str_icmp(charset, charset_types::utf16le)) + else if(utility::details::str_iequal(charset, charset_types::utf16le)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); @@ -843,7 +843,7 @@ json::value details::http_msg_base::_extract_json(bool ignore_content_type) } // utf-16be - else if(utility::details::str_icmp(charset, charset_types::utf16be)) + else if(utility::details::str_iequal(charset, charset_types::utf16be)) { utf16string body; body.resize(buf_r.in_avail() / sizeof(utf16string::value_type)); @@ -898,7 +898,7 @@ static utility::string_t convert_body_to_string_t(const utility::string_t &conte } // Latin1 - if(utility::details::str_icmp(charset, charset_types::latin1)) + if(utility::details::str_iequal(charset, charset_types::latin1)) { std::string body; body.resize(streambuf.in_avail()); @@ -907,7 +907,7 @@ static utility::string_t convert_body_to_string_t(const utility::string_t &conte } // utf-8. - else if(utility::details::str_icmp(charset, charset_types::utf8)) + else if(utility::details::str_iequal(charset, charset_types::utf8)) { std::string body; body.resize(streambuf.in_avail()); @@ -916,7 +916,7 @@ static utility::string_t convert_body_to_string_t(const utility::string_t &conte } // utf-16. - else if(utility::details::str_icmp(charset, charset_types::utf16)) + else if(utility::details::str_iequal(charset, charset_types::utf16)) { utf16string body; body.resize(streambuf.in_avail() / sizeof(utf16string::value_type)); @@ -925,7 +925,7 @@ static utility::string_t convert_body_to_string_t(const utility::string_t &conte } // utf-16le - else if(utility::details::str_icmp(charset, charset_types::utf16le)) + else if(utility::details::str_iequal(charset, charset_types::utf16le)) { utf16string body; body.resize(streambuf.in_avail() / sizeof(utf16string::value_type)); @@ -934,7 +934,7 @@ static utility::string_t convert_body_to_string_t(const utility::string_t &conte } // utf-16be - else if(utility::details::str_icmp(charset, charset_types::utf16be)) + else if(utility::details::str_iequal(charset, charset_types::utf16be)) { utf16string body; body.resize(streambuf.in_avail() / sizeof(utf16string::value_type)); @@ -1081,4 +1081,3 @@ const http_version http_versions::HTTP_1_1 = { 1, 1 }; #undef DAT #endif }} // namespace web::http - diff --git a/Release/src/http/oauth/oauth2.cpp b/Release/src/http/oauth/oauth2.cpp index e133a65202..247241933f 100644 --- a/Release/src/http/oauth/oauth2.cpp +++ b/Release/src/http/oauth/oauth2.cpp @@ -101,7 +101,7 @@ pplx::task oauth2_config::_request_token(uri_builder& request_body_ub) http_request request; request.set_method(methods::POST); request.set_request_uri(utility::string_t()); - + if(!user_agent().empty()) { request.headers().add(web::http::header_names::user_agent, user_agent()); @@ -169,7 +169,7 @@ oauth2_token oauth2_config::_parse_token_from_json(const json::value& token_json // As workaround we act as if 'token_type=bearer' was received. result.set_token_type(oauth2_strings::bearer); } - if (!utility::details::str_icmp(result.token_type(), oauth2_strings::bearer)) + if (!utility::details::str_iequal(result.token_type(), oauth2_strings::bearer)) { throw oauth2_exception(U("only 'token_type=bearer' access tokens are currently supported: ") + token_json.serialize()); } @@ -189,7 +189,7 @@ oauth2_token oauth2_config::_parse_token_from_json(const json::value& token_json if (json_expires_in_val.is_number()) result.set_expires_in(json_expires_in_val.as_number().to_int64()); - else + else { // Handle the case of a number as a JSON "string". // Using streams because std::stoll isn't avaliable on Android. diff --git a/Release/src/uri/uri.cpp b/Release/src/uri/uri.cpp index 4c06e52e2b..737ed12e1b 100644 --- a/Release/src/uri/uri.cpp +++ b/Release/src/uri/uri.cpp @@ -343,11 +343,7 @@ namespace if (scheme_begin) { components.m_scheme.assign(scheme_begin, scheme_end); - - // convert scheme to lowercase - std::transform(components.m_scheme.begin(), components.m_scheme.end(), components.m_scheme.begin(), [](utility::char_t c) { - return (utility::char_t)tolower(c); - }); + utility::details::inplace_tolower(components.m_scheme); } else { @@ -362,11 +358,7 @@ namespace if (host_begin) { components.m_host.assign(host_begin, host_end); - - // convert host to lowercase - std::transform(components.m_host.begin(), components.m_host.end(), components.m_host.begin(), [](utility::char_t c) { - return (utility::char_t)tolower(c); - }); + utility::details::inplace_tolower(components.m_host); } else { @@ -438,14 +430,9 @@ utility::string_t uri_components::join() // canonicalize components first // convert scheme to lowercase - std::transform(m_scheme.begin(), m_scheme.end(), m_scheme.begin(), [](utility::char_t c) { - return (utility::char_t)tolower(c); - }); - + utility::details::inplace_tolower(m_scheme); // convert host to lowercase - std::transform(m_host.begin(), m_host.end(), m_host.begin(), [](utility::char_t c) { - return (utility::char_t)tolower(c); - }); + utility::details::inplace_tolower(m_host); // canonicalize the path to have a leading slash if it's a full uri if (!m_host.empty() && m_path.empty()) diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index be38907c6e..893de3729b 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -12,6 +12,9 @@ ****/ #include "stdafx.h" +#include +#include +#include #ifndef _WIN32 #if defined(__clang__) @@ -29,12 +32,94 @@ using namespace web; using namespace utility; using namespace utility::conversions; +namespace +{ + struct to_lower_ch_impl + { + char operator()(char c) const CPPREST_NOEXCEPT + { + if (c >= 'A' && c <= 'Z') + return static_cast(c - 'A' + 'a'); + return c; + } + + wchar_t operator()(wchar_t c) const CPPREST_NOEXCEPT + { + if (c >= L'A' && c <= L'Z') + return static_cast(c - L'A' + L'a'); + return c; + } + }; + + constexpr to_lower_ch_impl to_lower_ch; + + struct eq_lower_ch_impl + { + template + inline CharT operator()(const CharT left, const CharT right) const CPPREST_NOEXCEPT + { + return to_lower_ch(left) == to_lower_ch(right); + } + }; + + constexpr eq_lower_ch_impl eq_lower_ch; + + struct lt_lower_ch_impl + { + template + inline CharT operator()(const CharT left, const CharT right) const CPPREST_NOEXCEPT + { + return to_lower_ch(left) < to_lower_ch(right); + } + }; + + constexpr lt_lower_ch_impl lt_lower_ch; +} + namespace utility { namespace details { +_ASYNCRTIMP bool __cdecl str_iequal(const std::string &left, const std::string &right) CPPREST_NOEXCEPT +{ + return left.size() == right.size() + && std::equal(left.cbegin(), left.cend(), right.cbegin(), eq_lower_ch); +} + +_ASYNCRTIMP bool __cdecl str_iequal(const std::wstring &left, const std::wstring &right) CPPREST_NOEXCEPT +{ + return left.size() == right.size() + && std::equal(left.cbegin(), left.cend(), right.cbegin(), eq_lower_ch); +} + +_ASYNCRTIMP bool __cdecl str_iless(const std::string &left, const std::string &right) CPPREST_NOEXCEPT +{ + return std::lexicographical_compare(left.cbegin(), left.cend(), right.cbegin(), right.cend(), lt_lower_ch); +} + +_ASYNCRTIMP bool __cdecl str_iless(const std::wstring &left, const std::wstring &right) CPPREST_NOEXCEPT +{ + return std::lexicographical_compare(left.cbegin(), left.cend(), right.cbegin(), right.cend(), lt_lower_ch); +} + +_ASYNCRTIMP void __cdecl inplace_tolower(std::string &target) CPPREST_NOEXCEPT +{ + for (auto& ch : target) + { + ch = to_lower_ch(ch); + } +} + +_ASYNCRTIMP void __cdecl inplace_tolower(std::wstring &target) CPPREST_NOEXCEPT +{ + for (auto& ch : target) + { + ch = to_lower_ch(ch); + } +} + #if !defined(ANDROID) && !defined(__ANDROID__) std::once_flag g_c_localeFlag; std::unique_ptr g_c_locale(nullptr, [](scoped_c_thread_locale::xplat_locale *){}); @@ -205,7 +290,7 @@ std::error_condition windows_category_impl::default_error_condition(int errorCod // First see if the STL implementation can handle the mapping for common cases. const std::error_condition errCondition = std::system_category().default_error_condition(errorCode); const std::string errConditionMsg = errCondition.message(); - if(_stricmp(errConditionMsg.c_str(), "unknown error") != 0) + if(!utility::details::str_iequal(errConditionMsg, "unknown error")) { return errCondition; } @@ -346,7 +431,7 @@ utf16string __cdecl conversions::utf8_to_utf16(const std::string &s) utf16string dest(count_utf8_to_utf16(s), L'\0'); utf16string::value_type* const destData = &dest[0]; size_t destIndex = 0; - + for (size_t index = 0; index < srcSize; ++index) { std::string::value_type src = srcData[index]; diff --git a/Release/src/websockets/client/ws_client_winrt.cpp b/Release/src/websockets/client/ws_client_winrt.cpp index c7197947df..38b4f7989d 100644 --- a/Release/src/websockets/client/ws_client_winrt.cpp +++ b/Release/src/websockets/client/ws_client_winrt.cpp @@ -86,7 +86,7 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: { // Unfortunately the MessageWebSocket API throws a COMException if you try to set the // 'Sec-WebSocket-Protocol' header here. It requires you to go through their API instead. - if (!utility::details::str_icmp(header.first, protocolHeader)) + if (!utility::details::str_iequal(header.first, protocolHeader)) { m_msg_websocket->SetRequestHeader(Platform::StringReference(header.first.c_str()), Platform::StringReference(header.second.c_str())); } @@ -171,7 +171,7 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: std::weak_ptr thisWeakPtr = shared_from_this(); return pplx::create_task(m_msg_websocket->ConnectAsync(uri)).then([thisWeakPtr](pplx::task result) -> pplx::task { - // result.get() should happen before anything else, to make sure there is no unobserved exception + // result.get() should happen before anything else, to make sure there is no unobserved exception // in the task chain. try { @@ -421,7 +421,7 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: // External callback for handling received and close event std::function m_external_message_handler; std::function m_external_close_handler; - + // Queue to track pending sends outgoing_msg_queue m_out_queue; }; diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index 8f2658a8f5..66b85744f4 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -338,7 +338,7 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: // Add any request headers specified by the user. for (const auto & header : headers) { - if (!utility::details::str_icmp(header.first, g_subProtocolHeader)) + if (!utility::details::str_iequal(header.first, g_subProtocolHeader)) { con->append_header(utility::conversions::to_utf8string(header.first), utility::conversions::to_utf8string(header.second)); } @@ -806,4 +806,3 @@ websocket_callback_client::websocket_callback_client(websocket_client_config con }}} #endif -