diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index a38702f412..4166eb8c48 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -373,6 +373,26 @@ inline bool __cdecl is_alnum(Elem ch) CPPREST_NOEXCEPT return (uch <= static_cast('z') && is_alnum(static_cast(uch))); } +/// +/// Our own implementation of whitespace test instead of std::isspace to avoid +/// taking global lock for performance reasons. +/// The following characters are considered whitespace: +/// 0x09 == Horizontal Tab +/// 0x0A == Line Feed +/// 0x0B == Vertical Tab +/// 0x0C == Form Feed +/// 0x0D == Carrage Return +/// 0x20 == Space +/// +template +inline bool __cdecl is_space(Elem ch) CPPREST_NOEXCEPT +{ + // assumes 'x' == L'x' for the ASCII range + typedef typename std::make_unsigned::type UElem; + const auto uch = static_cast(ch); + return uch == 0x20u || (uch >= 0x09u && uch <= 0x0Du); +} + /// /// Simplistic implementation of make_unique. A better implementation would be based on variadic templates /// and therefore not be compatible with Dev10. diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 249bfcd52c..f4b97f509a 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -15,6 +15,7 @@ #include "stdafx.h" #include "../common/x509_cert_utilities.h" +#include "../common/internal_http_helpers.h" #include "cpprest/http_headers.h" #include "http_client_impl.h" #include @@ -99,51 +100,6 @@ static http::status_code parse_status_code(HINTERNET request_handle) return (unsigned short)_wtoi(buffer.c_str()); } -// Helper function to trim leading and trailing null characters from a string. -static void trim_nulls(utility::string_t& str) -{ - if (str.empty()) - { - return; - } - - auto first = str.begin(); - auto last = str.end(); - - if (*first) - { - --last; - if (*last) - { - // no nulls to remove - return; - } - - // nulls at the back to remove - do - { - --last; - } while (*last == utility::char_t {}); - ++last; - str.erase(last, str.end()); - return; - } - - // nulls at the front, and maybe the back, to remove - first = std::find_if(str.begin(), last, [](const utility::char_t c) { return c != utility::char_t {}; }); - - if (first != last) - { - do - { - --last; - } while (*last == utility::char_t {}); - ++last; - } - - str.assign(first, last); -} - // Helper function to get the reason phrase from a WinHTTP response. static utility::string_t parse_reason_phrase(HINTERNET request_handle) { @@ -159,7 +115,7 @@ static utility::string_t parse_reason_phrase(HINTERNET request_handle) &length, WINHTTP_NO_HEADER_INDEX); // WinHTTP reports back the wrong length, trim any null characters. - trim_nulls(phrase); + ::web::http::details::trim_nulls(phrase); return phrase; } diff --git a/Release/src/http/common/internal_http_helpers.h b/Release/src/http/common/internal_http_helpers.h index 2270f7b955..1fbdfdfa58 100644 --- a/Release/src/http/common/internal_http_helpers.h +++ b/Release/src/http/common/internal_http_helpers.h @@ -5,6 +5,7 @@ #pragma once +#include "cpprest/asyncrt_utils.h" #include "cpprest/details/basic_types.h" #include @@ -19,19 +20,71 @@ namespace details /// utility::string_t get_default_reason_phrase(status_code code); -// simple helper functions to trim whitespace. +template +void trim_if(std::basic_string& str, Fn test) +{ + if (str.empty()) + { + return; + } + + auto first = str.begin(); + auto last = str.end(); + + if (test(*first)) + { + // removals at the front, and maybe the back + for (;;) + { + ++first; + if (first == last) + { + // all removals + str.clear(); + return; + } + + if (!test(*first)) + { + break; + } + } + + do + { + --last; + } while (test(*last)); + ++last; + str.assign(first, last); + return; + } + + // no removals at the front, only maybe the back + --last; + if (!test(*last)) + { + // no removals at all + return; + } + + do + { + --last; + } while (test(*last)); + ++last; + str.erase(last, str.end()); +} + +template +void trim_nulls(std::basic_string& str) +{ + trim_if(str, [](const Char c) { return c == Char {}; }); +} + template void trim_whitespace(std::basic_string& str) { - size_t index; - // trim left whitespace - for (index = 0; index < str.size() && isspace(str[index]); ++index) - ; - str.erase(0, index); - // trim right whitespace - for (index = str.size(); index > 0 && isspace(str[index - 1]); --index) - ; - str.erase(index); + trim_if(str, [](const Char c) { return ::utility::details::is_space(c); }); } bool validate_method(const utility::string_t& method);