From a70be339e7ea3900db38408e744a0bbd22b7b1d6 Mon Sep 17 00:00:00 2001 From: Anton Kolesnyk <41349689+antkmsft@users.noreply.github.com> Date: Tue, 3 Jan 2023 11:16:54 -0800 Subject: [PATCH] Audit string comparisons (#4197) * Audit string comparisons * Mac fix * !isxdigit() * Rewrite condition + comment * <3 * Clang-format * 255 * Allow uppercase * stoi() radix * ShouldEncode() Co-authored-by: Anton Kolesnyk --- samples/helpers/get-env/src/get_env.cpp | 4 +- .../policy-certificates/cryptohelpers.hpp | 12 +- .../inc/azure/core/test/test_base.hpp | 3 +- sdk/core/azure-core/CMakeLists.txt | 1 - .../azure-core/inc/azure/core/http/http.hpp | 2 +- .../inc/azure/core/internal/strings.hpp | 56 +++++- sdk/core/azure-core/inc/azure/core/url.hpp | 5 - sdk/core/azure-core/src/datetime.cpp | 16 +- .../src/environment_log_level_listener.cpp | 27 ++- sdk/core/azure-core/src/http/curl/curl.cpp | 6 +- sdk/core/azure-core/src/http/http.cpp | 156 ++------------- sdk/core/azure-core/src/http/raw_response.cpp | 6 - sdk/core/azure-core/src/http/request.cpp | 31 ++- sdk/core/azure-core/src/http/url.cpp | 188 ++++++++++-------- sdk/core/azure-core/src/http/user_agent.cpp | 8 +- sdk/core/azure-core/src/strings.cpp | 133 ------------- sdk/core/azure-core/src/tracing/tracing.cpp | 1 - sdk/core/azure-core/test/ut/string_test.cpp | 12 +- .../src/azure_cli_credential.cpp | 4 +- .../src/key_rotation_policy.cpp | 13 +- .../inc/azure/storage/blobs/rest_client.hpp | 32 +-- .../src/shared_key_policy.cpp | 3 +- .../test/ut/test_base.cpp | 1 - .../storage/files/shares/rest_client.hpp | 32 +-- .../inc/azure/storage/queues/rest_client.hpp | 14 +- 25 files changed, 254 insertions(+), 512 deletions(-) delete mode 100644 sdk/core/azure-core/src/strings.cpp diff --git a/samples/helpers/get-env/src/get_env.cpp b/samples/helpers/get-env/src/get_env.cpp index 50921035e..cc72ce671 100644 --- a/samples/helpers/get-env/src/get_env.cpp +++ b/samples/helpers/get-env/src/get_env.cpp @@ -3,7 +3,7 @@ #include "get_env.hpp" -#include +#include #if defined(WINAPI_PARTITION_DESKTOP) && !WINAPI_PARTITION_DESKTOP @@ -20,7 +20,7 @@ char* std::getenv(const char* name) } // We're still trying to match the name. - if (std::toupper(*buf) == std::toupper(name[i])) + if (std::toupper(*buf, std::locale::classic()) == std::toupper(name[i], std::locale::classic())) { // Matching so far, keep matching name and buffer, char by char, case insensitive. ++i; diff --git a/sdk/attestation/azure-security-attestation/samples/policy-certificates/cryptohelpers.hpp b/sdk/attestation/azure-security-attestation/samples/policy-certificates/cryptohelpers.hpp index 1a5c36969..7dc9ce49e 100644 --- a/sdk/attestation/azure-security-attestation/samples/policy-certificates/cryptohelpers.hpp +++ b/sdk/attestation/azure-security-attestation/samples/policy-certificates/cryptohelpers.hpp @@ -1,6 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // SPDX-License-Identifier: MIT #pragma once + +#include + #include #include #include @@ -193,14 +196,9 @@ public: } hashedThumbprint.resize(hashLength); - auto hexThumbprint(BinaryToHexString(hashedThumbprint)); // HexString uses an "a"-"f" alphabet, but the CLR hex encoder uses an "A"-"F" alphabet, - // convert between them. - std::transform( - hexThumbprint.begin(), hexThumbprint.end(), hexThumbprint.begin(), [](char ch) { - return static_cast(std::toupper(ch)); - }); - return hexThumbprint; + // so we need to uppercase them. + return Azure::Core::_internal::StringExtensions::ToUpper(BinaryToHexString(hashedThumbprint)); } static std::unique_ptr Import( diff --git a/sdk/core/azure-core-test/inc/azure/core/test/test_base.hpp b/sdk/core/azure-core-test/inc/azure/core/test/test_base.hpp index 6c1a9407c..a5f3c0be8 100644 --- a/sdk/core/azure-core-test/inc/azure/core/test/test_base.hpp +++ b/sdk/core/azure-core-test/inc/azure/core/test/test_base.hpp @@ -186,8 +186,7 @@ namespace Azure { namespace Core { namespace Test { // creating std::string GetTestNameLowerCase(bool sanitize = true) { - std::string testName(GetTestName(sanitize)); - return Azure::Core::_internal::StringExtensions::ToLower(testName); + return Azure::Core::_internal::StringExtensions::ToLower(GetTestName(sanitize)); } /** diff --git a/sdk/core/azure-core/CMakeLists.txt b/sdk/core/azure-core/CMakeLists.txt index ae4bad15a..117c1a42c 100644 --- a/sdk/core/azure-core/CMakeLists.txt +++ b/sdk/core/azure-core/CMakeLists.txt @@ -147,7 +147,6 @@ set( src/operation_status.cpp src/private/environment_log_level_listener.hpp src/private/package_version.hpp - src/strings.cpp src/tracing/tracing.cpp src/uuid.cpp ) diff --git a/sdk/core/azure-core/inc/azure/core/http/http.hpp b/sdk/core/azure-core/inc/azure/core/http/http.hpp index a8c8247ab..cd0066af6 100644 --- a/sdk/core/azure-core/inc/azure/core/http/http.hpp +++ b/sdk/core/azure-core/inc/azure/core/http/http.hpp @@ -363,7 +363,7 @@ namespace Azure { namespace Core { namespace Http { } // Always toLower() headers - auto headerName + auto const headerName = Azure::Core::_internal::StringExtensions::ToLower(std::string(start, end)); start = end + 1; // start value while (start < last && (*start == ' ' || *start == '\t')) diff --git a/sdk/core/azure-core/inc/azure/core/internal/strings.hpp b/sdk/core/azure-core/inc/azure/core/internal/strings.hpp index 0858c230e..d7e47ad91 100644 --- a/sdk/core/azure-core/inc/azure/core/internal/strings.hpp +++ b/sdk/core/azure-core/inc/azure/core/internal/strings.hpp @@ -9,6 +9,7 @@ #pragma once #include +#include #include namespace Azure { namespace Core { namespace _internal { @@ -19,24 +20,61 @@ namespace Azure { namespace Core { namespace _internal { */ struct StringExtensions final { + static constexpr char ToUpper(char c) noexcept + { + return (c < 'a' || c > 'z') ? c : c - ('a' - 'A'); + } + + static constexpr char ToLower(char c) noexcept + { + return (c < 'A' || c > 'Z') ? c : c + ('a' - 'A'); + } + struct CaseInsensitiveComparator final { - bool operator()(const std::string& lhs, const std::string& rhs) const + bool operator()(std::string const& lhs, std::string const& rhs) const { return std::lexicographical_compare( - lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](char c1, char c2) { - return ToLower(c1) < ToLower(c2); + lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](auto l, auto r) { + return ToLower(l) < ToLower(r); }); } }; static bool LocaleInvariantCaseInsensitiveEqual( - const std::string& lhs, - const std::string& rhs) noexcept; - static std::string const ToLower(std::string const& src) noexcept; - static unsigned char ToLower(unsigned char const src) noexcept; - static std::string const ToUpper(std::string const& src) noexcept; - static unsigned char ToUpper(unsigned char const src) noexcept; + std::string const& lhs, + std::string const& rhs) noexcept + { + auto const rhsSize = rhs.size(); + if (lhs.size() != rhsSize) + { + return false; + } + + auto const lhsData = lhs.c_str(); + auto const rhsData = rhs.c_str(); + for (size_t i = 0; i < rhsSize; ++i) + { + if (ToLower(lhsData[i]) != ToLower(rhsData[i])) + { + return false; + } + } + + return true; + } + + static std::string ToLower(std::string src) + { + std::transform(src.begin(), src.end(), src.begin(), [](auto c) { return ToLower(c); }); + return src; + } + + static std::string ToUpper(std::string src) + { + std::transform(src.begin(), src.end(), src.begin(), [](auto c) { return ToUpper(c); }); + return src; + } }; }}} // namespace Azure::Core::_internal diff --git a/sdk/core/azure-core/inc/azure/core/url.hpp b/sdk/core/azure-core/inc/azure/core/url.hpp index 4058e626c..28cf1d80c 100644 --- a/sdk/core/azure-core/inc/azure/core/url.hpp +++ b/sdk/core/azure-core/inc/azure/core/url.hpp @@ -14,7 +14,6 @@ #include #include #include -#include namespace Azure { namespace Core { namespace _detail { @@ -53,10 +52,6 @@ namespace Azure { namespace Core { // query parameters are all encoded std::map m_encodedQueryParameters; - // List of default non-URL-encode chars. While URL encoding a string, do not escape any chars in - // this set. - const static std::unordered_set defaultNonUrlEncodeChars; - std::string GetUrlWithoutQuery(bool relative) const; /** diff --git a/sdk/core/azure-core/src/datetime.cpp b/sdk/core/azure-core/src/datetime.cpp index 7c0152dad..0d653b1b0 100644 --- a/sdk/core/azure-core/src/datetime.cpp +++ b/sdk/core/azure-core/src/datetime.cpp @@ -5,10 +5,10 @@ #include "azure/core/platform.hpp" #include -#include #include #include #include +#include #include #include @@ -319,10 +319,10 @@ T ParseNumber( auto i = 0; for (; i < MaxChars; ++i) { - int const ch = str[*cursor + i]; - if (std::isdigit(ch)) + auto const ch = str[*cursor + i]; + if (std::isdigit(ch, std::locale::classic())) { - value = (value * 10) + (static_cast(ch) - '0'); + value = (value * 10) + (static_cast(static_cast(ch)) - '0'); continue; } @@ -654,10 +654,10 @@ DateTime DateTime::Parse(std::string const& dateTime, DateFormat format) minDateTimeLength += charsRead; if (charsRead == 7 && (DateTimeLength - cursor) > 0) { - int const ch = dateTime[cursor]; - if (std::isdigit(ch)) + auto const ch = dateTime[cursor]; + if (std::isdigit(ch, std::locale::classic())) { - auto const num = static_cast(ch - '0'); + auto const num = static_cast(static_cast(ch) - '0'); if (num > 4) { if (fracSec < 9999999) @@ -677,7 +677,7 @@ DateTime DateTime::Parse(std::string const& dateTime, DateFormat format) for (auto i = DateTimeLength - cursor; i > 0; --i) { - if (std::isdigit(static_cast(dateTime[cursor]))) + if (std::isdigit(dateTime[cursor], std::locale::classic())) { ++minDateTimeLength; ++cursor; diff --git a/sdk/core/azure-core/src/environment_log_level_listener.cpp b/sdk/core/azure-core/src/environment_log_level_listener.cpp index a79ad911c..d20347644 100644 --- a/sdk/core/azure-core/src/environment_log_level_listener.cpp +++ b/sdk/core/azure-core/src/environment_log_level_listener.cpp @@ -25,33 +25,42 @@ Logger::Level const* GetEnvironmentLogLevel() { EnvironmentLogLevelListener::SetInitialized(true); - auto const envVar = Environment::GetVariable("AZURE_LOG_LEVEL"); - if (!envVar.empty()) + auto const logLevelStr = Environment::GetVariable("AZURE_LOG_LEVEL"); + if (!logLevelStr.empty()) { - auto const logLevelStr = Azure::Core::_internal::StringExtensions::ToLower(envVar); - // See https://github.com/Azure/azure-sdk-for-java/wiki/Logging-with-Azure-SDK // And // https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/core/azure-core/src/main/java/com/azure/core/util/logging/LogLevel.java + using Azure::Core::_internal::StringExtensions; static Logger::Level envLogLevel = {}; envLogLevelPtr = &envLogLevel; - if (logLevelStr == "error" || logLevelStr == "err" || logLevelStr == "4") + if (logLevelStr == "4" + || StringExtensions::LocaleInvariantCaseInsensitiveEqual(logLevelStr, "error") + || StringExtensions::LocaleInvariantCaseInsensitiveEqual(logLevelStr, "err")) { envLogLevel = Logger::Level::Error; } - else if (logLevelStr == "warning" || logLevelStr == "warn" || logLevelStr == "3") + else if ( + logLevelStr == "3" + || StringExtensions::LocaleInvariantCaseInsensitiveEqual(logLevelStr, "warning") + || StringExtensions::LocaleInvariantCaseInsensitiveEqual(logLevelStr, "warn")) { envLogLevel = Logger::Level::Warning; } else if ( - logLevelStr == "informational" || logLevelStr == "info" || logLevelStr == "information" - || logLevelStr == "2") + logLevelStr == "2" + || StringExtensions::LocaleInvariantCaseInsensitiveEqual(logLevelStr, "informational") + || StringExtensions::LocaleInvariantCaseInsensitiveEqual(logLevelStr, "information") + || StringExtensions::LocaleInvariantCaseInsensitiveEqual(logLevelStr, "info")) { envLogLevel = Logger::Level::Informational; } - else if (logLevelStr == "verbose" || logLevelStr == "debug" || logLevelStr == "1") + else if ( + logLevelStr == "1" + || StringExtensions::LocaleInvariantCaseInsensitiveEqual(logLevelStr, "verbose") + || StringExtensions::LocaleInvariantCaseInsensitiveEqual(logLevelStr, "debug")) { envLogLevel = Logger::Level::Verbose; } diff --git a/sdk/core/azure-core/src/http/curl/curl.cpp b/sdk/core/azure-core/src/http/curl/curl.cpp index f8467e0cc..cba942bec 100644 --- a/sdk/core/azure-core/src/http/curl/curl.cpp +++ b/sdk/core/azure-core/src/http/curl/curl.cpp @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -1315,9 +1316,10 @@ void DumpCurlInfoToLog(std::string const& text, uint8_t* ptr, size_t size) { // Log the contents of the buffer as text, if it's printable, print the character, otherwise // print '.' - if (isprint(ptr[i + c])) + auto const ch = static_cast(ptr[i + c]); + if (std::isprint(ch, std::locale::classic())) { - ss << ptr[i + c]; + ss << ch; } else { diff --git a/sdk/core/azure-core/src/http/http.cpp b/sdk/core/azure-core/src/http/http.cpp index 7a3b3edb6..4d05ece7f 100644 --- a/sdk/core/azure-core/src/http/http.cpp +++ b/sdk/core/azure-core/src/http/http.cpp @@ -6,6 +6,9 @@ #include "azure/core/internal/io/null_body_stream.hpp" #include "azure/core/url.hpp" +#include +#include +#include #include using namespace Azure::Core; @@ -25,153 +28,30 @@ const HttpMethod HttpMethod::Put("PUT"); const HttpMethod HttpMethod::Delete("DELETE"); const HttpMethod HttpMethod::Patch("PATCH"); +namespace { +bool IsInvalidHeaderNameChar(char c) +{ + static std::unordered_set const HeaderNameExtraValidChars + = {' ', '!', '#', '$', '%', '&', '\'', '*', '+', '-', '.', '^', '_', '`', '|', '~'}; + + return !std::isalnum(c, std::locale::classic()) + && HeaderNameExtraValidChars.find(c) == HeaderNameExtraValidChars.end(); +} +} // namespace + void Azure::Core::Http::_detail::RawResponseHelpers::InsertHeaderWithValidation( Azure::Core::CaseInsensitiveMap& headers, std::string const& headerName, std::string const& headerValue) { - // Static table for validating header names. It is created just once for the program and reused - // each time SetHeader is called - static const uint8_t validChars[256] = { - 0, /* 0 - null */ - 0, /* 1 - start of heading */ - 0, /* 2 - start of text */ - 0, /* 3 - end of text */ - 0, /* 4 - end of transmission */ - 0, /* 5 - enquiry */ - 0, /* 6 - acknowledge */ - 0, /* 7 - bell */ - 0, /* 8 - backspace */ - 0, /* 9 - horizontal tab */ - 0, /* 10 - new line */ - 0, /* 11 - vertical tab */ - 0, /* 12 - new page */ - 0, /* 13 - carriage return */ - 0, /* 14 - shift out */ - 0, /* 15 - shift in */ - 0, /* 16 - data link escape */ - 0, /* 17 - device control 1 */ - 0, /* 18 - device control 2 */ - 0, /* 19 - device control 3 */ - 0, /* 20 - device control 4 */ - 0, /* 21 - negative acknowledge */ - 0, /* 22 - synchronous idle */ - 0, /* 23 - end of trans. block */ - 0, /* 24 - cancel */ - 0, /* 25 - end of medium */ - 0, /* 26 - substitute */ - 0, /* 27 - escape */ - 0, /* 28 - file separator */ - 0, /* 29 - group separator */ - 0, /* 30 - record separator */ - 0, /* 31 - unit separator */ - ' ', /* 32 - space */ - '!', /* 33 - ! */ - 0, /* 34 - " */ - '#', /* 35 - # */ - '$', /* 36 - $ */ - '%', /* 37 - % */ - '&', /* 38 - & */ - '\'', /* 39 - ' */ - 0, /* 40 - ( */ - 0, /* 41 - ) */ - '*', /* 42 - * */ - '+', /* 43 - + */ - 0, /* 44 - , */ - '-', /* 45 - - */ - '.', /* 46 - . */ - 0, /* 47 - / */ - '0', /* 48 - 0 */ - '1', /* 49 - 1 */ - '2', /* 50 - 2 */ - '3', /* 51 - 3 */ - '4', /* 52 - 4 */ - '5', /* 53 - 5 */ - '6', /* 54 - 6 */ - '7', /* 55 - 7 */ - '8', /* 56 - 8 */ - '9', /* 57 - 9 */ - 0, /* 58 - : */ - 0, /* 59 - ; */ - 0, /* 60 - < */ - 0, /* 61 - = */ - 0, /* 62 - > */ - 0, /* 63 - ? */ - 0, /* 64 - @ */ - 'a', /* 65 - A */ - 'b', /* 66 - B */ - 'c', /* 67 - C */ - 'd', /* 68 - D */ - 'e', /* 69 - E */ - 'f', /* 70 - F */ - 'g', /* 71 - G */ - 'h', /* 72 - H */ - 'i', /* 73 - I */ - 'j', /* 74 - J */ - 'k', /* 75 - K */ - 'l', /* 76 - L */ - 'm', /* 77 - M */ - 'n', /* 78 - N */ - 'o', /* 79 - O */ - 'p', /* 80 - P */ - 'q', /* 81 - Q */ - 'r', /* 82 - R */ - 's', /* 83 - S */ - 't', /* 84 - T */ - 'u', /* 85 - U */ - 'v', /* 86 - V */ - 'w', /* 87 - W */ - 'x', /* 88 - X */ - 'y', /* 89 - Y */ - 'z', /* 90 - Z */ - 0, /* 91 - [ */ - 0, /* 92 - comment */ - 0, /* 93 - ] */ - '^', /* 94 - ^ */ - '_', /* 95 - _ */ - '`', /* 96 - ` */ - 'a', /* 97 - a */ - 'b', /* 98 - b */ - 'c', /* 99 - c */ - 'd', /* 100 - d */ - 'e', /* 101 - e */ - 'f', /* 102 - f */ - 'g', /* 103 - g */ - 'h', /* 104 - h */ - 'i', /* 105 - i */ - 'j', /* 106 - j */ - 'k', /* 107 - k */ - 'l', /* 108 - l */ - 'm', /* 109 - m */ - 'n', /* 110 - n */ - 'o', /* 111 - o */ - 'p', /* 112 - p */ - 'q', /* 113 - q */ - 'r', /* 114 - r */ - 's', /* 115 - s */ - 't', /* 116 - t */ - 'u', /* 117 - u */ - 'v', /* 118 - v */ - 'w', /* 119 - w */ - 'x', /* 120 - x */ - 'y', /* 121 - y */ - 'z', /* 122 - z */ - 0, /* 123 - { */ - '|', /* 124 - | */ - 0, /* 125 - } */ - '~', /* 126 - ~ */ - 0 /* 127 - DEL */ - // ...128-255 is all zeros (not valid) characters} - }; // Check all chars in name are valid - for (size_t index = 0; index < headerName.size(); index++) + if (std::find_if(headerName.begin(), headerName.end(), IsInvalidHeaderNameChar) + != headerName.end()) { - if (validChars[static_cast(headerName[index])] == 0) - { - throw std::invalid_argument("Invalid header: " + headerName); - } + throw std::invalid_argument("Invalid header name: " + headerName); } + // insert (override if duplicated) headers[headerName] = headerValue; } diff --git a/sdk/core/azure-core/src/http/raw_response.cpp b/sdk/core/azure-core/src/http/raw_response.cpp index 213630cff..f3316d3b3 100644 --- a/sdk/core/azure-core/src/http/raw_response.cpp +++ b/sdk/core/azure-core/src/http/raw_response.cpp @@ -3,12 +3,6 @@ #include "azure/core/http/raw_response.hpp" #include "azure/core/http/http.hpp" -#include "azure/core/internal/strings.hpp" - -#include -#include -#include -#include using namespace Azure::Core::IO; using namespace Azure::Core::Http; diff --git a/sdk/core/azure-core/src/http/request.cpp b/sdk/core/azure-core/src/http/request.cpp index ba768de9a..be4b2a83f 100644 --- a/sdk/core/azure-core/src/http/request.cpp +++ b/sdk/core/azure-core/src/http/request.cpp @@ -24,29 +24,24 @@ static Azure::Core::CaseInsensitiveMap MergeMaps( Azure::Nullable Request::GetHeader(std::string const& name) { - std::vector returnedHeaders; - auto headerNameLowerCase = Azure::Core::_internal::StringExtensions::ToLower(name); + for (auto const& hdrs : {m_retryHeaders, m_headers}) + { + auto const header = hdrs.find(name); + if (header != hdrs.end()) + { + return header->second; + } + } - auto retryHeader = this->m_retryHeaders.find(headerNameLowerCase); - if (retryHeader != this->m_retryHeaders.end()) - { - return retryHeader->second; - } - auto header = this->m_headers.find(headerNameLowerCase); - if (header != this->m_headers.end()) - { - return header->second; - } - return Azure::Nullable{}; + return {}; } void Request::SetHeader(std::string const& name, std::string const& value) { - auto headerNameLowerCase = Azure::Core::_internal::StringExtensions::ToLower(name); - return this->m_retryModeEnabled ? _detail::RawResponseHelpers::InsertHeaderWithValidation( - this->m_retryHeaders, headerNameLowerCase, value) - : _detail::RawResponseHelpers::InsertHeaderWithValidation( - this->m_headers, headerNameLowerCase, value); + return _detail::RawResponseHelpers::InsertHeaderWithValidation( + m_retryModeEnabled ? m_retryHeaders : m_headers, + Azure::Core::_internal::StringExtensions::ToLower(name), + value); } void Request::RemoveHeader(std::string const& name) diff --git a/sdk/core/azure-core/src/http/url.cpp b/sdk/core/azure-core/src/http/url.cpp index 85b58af8b..6304ca55b 100644 --- a/sdk/core/azure-core/src/http/url.cpp +++ b/sdk/core/azure-core/src/http/url.cpp @@ -5,145 +5,165 @@ #include "azure/core/internal/strings.hpp" #include -#include -#include #include +#include #include -#include +#include using namespace Azure::Core; -Url::Url(const std::string& url) +Url::Url(std::string const& url) { - std::string::const_iterator pos = url.begin(); + auto urlIter = url.cbegin(); - const std::string schemeEnd = "://"; - auto schemeIter = url.find(schemeEnd); - if (schemeIter != std::string::npos) { - std::transform(url.begin(), url.begin() + schemeIter, std::back_inserter(m_scheme), [](char c) { - return static_cast( - Azure::Core::_internal::StringExtensions::ToLower(static_cast(c))); - }); + std::string const SchemeEnd = "://"; + auto const schemePos = url.find(SchemeEnd); - pos = url.begin() + schemeIter + schemeEnd.length(); + if (schemePos != std::string::npos) + { + m_scheme = Azure::Core::_internal::StringExtensions::ToLower(url.substr(0, schemePos)); + urlIter += schemePos + SchemeEnd.length(); + } } - auto hostIter - = std::find_if(pos, url.end(), [](char c) { return c == '/' || c == '?' || c == ':'; }); - m_host = std::string(pos, hostIter); - pos = hostIter; - - if (pos != url.end() && *pos == ':') { - auto port_ite = std::find_if_not( - pos + 1, url.end(), [](char c) { return std::isdigit(static_cast(c)); }); - auto portNumber = std::stoi(std::string(pos + 1, port_ite)); + auto const hostIter + = std::find_if(urlIter, url.end(), [](auto c) { return c == '/' || c == '?' || c == ':'; }); + + m_host = std::string(urlIter, hostIter); + urlIter = hostIter; + } + + if (urlIter == url.end()) + { + return; + } + + if (*urlIter == ':') + { + ++urlIter; + auto const portIter = std::find_if_not( + urlIter, url.end(), [](auto c) { return std::isdigit(c, std::locale::classic()); }); + + auto const portNumber = std::stoi(std::string(urlIter, portIter)); // stoi will throw out_of_range when `int` is overflow, but we need to throw if uint16 is // overflow - auto maxPortNumberSupported = std::numeric_limits::max(); - if (portNumber > maxPortNumberSupported) { - throw std::out_of_range( - "The port number is out of range. The max supported number is " - + std::to_string(maxPortNumberSupported) + "."); + constexpr auto const MaxPortNumberSupported = std::numeric_limits::max(); + if (portNumber > MaxPortNumberSupported) + { + throw std::out_of_range( + "The port number is out of range. The max supported number is " + + std::to_string(MaxPortNumberSupported) + "."); + } } + // cast is safe because the overflow was detected before m_port = static_cast(portNumber); - pos = port_ite; + urlIter = portIter; } - if (pos != url.end() && (*pos != '/') && (*pos != '?')) + if (urlIter == url.end()) { - // only char `\` or `?` is valid after the port (or the end of the URL). Any other char is an + return; + } + + if (*urlIter != '/' && *urlIter != '?') + { + // only char '/' or '?' is valid after the port (or the end of the URL). Any other char is an // invalid input throw std::invalid_argument("The port number contains invalid characters."); } - if (pos != url.end() && (*pos == '/')) + if (*urlIter == '/') { - auto pathIter = std::find(pos + 1, url.end(), '?'); - m_encodedPath = std::string(pos + 1, pathIter); - pos = pathIter; + ++urlIter; + + auto const pathIter = std::find(urlIter, url.end(), '?'); + m_encodedPath = std::string(urlIter, pathIter); + + urlIter = pathIter; } - if (pos != url.end() && *pos == '?') + if (urlIter != url.end() && *urlIter == '?') { - auto queryIter = std::find(pos + 1, url.end(), '#'); - AppendQueryParameters(std::string(pos + 1, queryIter)); - pos = queryIter; + ++urlIter; + AppendQueryParameters(std::string(urlIter, std::find(urlIter, url.end(), '#'))); } } -std::string Url::Decode(const std::string& value) +std::string Url::Decode(std::string const& value) { - const static std::vector hexTable = []() { - std::vector t(256, -1); - for (int i = 0; i < 10; ++i) - { - t[static_cast('0') + i] = i; - } - for (int i = 10; i < 16; ++i) - { - t[static_cast('A') + i - 10] = i; - t[static_cast('a') + i - 10] = i; - } - return t; - }(); - std::string decodedValue; - for (size_t i = 0; i < value.size();) + auto const valueSize = value.size(); + for (size_t i = 0; i < valueSize; ++i) { - char c = value[i]; - if (c == '+') + auto const c = value[i]; + switch (c) { - decodedValue += ' '; - ++i; - } - else if (c == '%') - { - if (i + 2 >= value.size() || hexTable[value[i + 1]] < 0 || hexTable[value[i + 2]] < 0) - { - throw std::runtime_error("failed when decoding URL component"); - } - int v = (hexTable[value[i + 1]] << 4) + hexTable[value[i + 2]]; - decodedValue += static_cast(v); - i += 3; - } - else - { - decodedValue += value[i]; - ++i; + case '%': + if ((valueSize - i) < 3 // need at least 3 characters: "%XY" + || !std::isxdigit(value[i + 1], std::locale::classic()) + || !std::isxdigit(value[i + 2], std::locale::classic())) + { + throw std::runtime_error("failed when decoding URL component"); + } + + decodedValue += static_cast(std::stoi(value.substr(i + 1, 2), nullptr, 16)); + i += 2; + break; + + case '+': + decodedValue += ' '; + break; + + default: + decodedValue += c; + break; } } + return decodedValue; } +namespace { +bool ShouldEncode(char c) +{ + static std::unordered_set const ExtraNonEncodableChars = {'-', '.', '_', '~'}; + + return !std::isalnum(c, std::locale::classic()) + && ExtraNonEncodableChars.find(c) == ExtraNonEncodableChars.end(); +} +} // namespace + std::string Url::Encode(const std::string& value, const std::string& doNotEncodeSymbols) { - const char* hex = "0123456789ABCDEF"; - std::unordered_set noEncodingSymbolsSet( + auto const Hex = "0123456789ABCDEF"; + + std::unordered_set const doNotEncodeSymbolsSet( doNotEncodeSymbols.begin(), doNotEncodeSymbols.end()); std::string encoded; - for (char c : value) + for (auto const c : value) { - unsigned char uc = c; // encode if char is not in the default non-encoding set AND if it is NOT in chars to ignore // from user input - if (defaultNonUrlEncodeChars.find(uc) == defaultNonUrlEncodeChars.end() - && noEncodingSymbolsSet.find(uc) == noEncodingSymbolsSet.end()) + if (ShouldEncode(c) && doNotEncodeSymbolsSet.find(c) == doNotEncodeSymbolsSet.end()) { + auto const u8 = static_cast(c); + encoded += '%'; - encoded += hex[(uc >> 4) & 0x0f]; - encoded += hex[uc & 0x0f]; + encoded += Hex[(u8 >> 4) & 0x0f]; + encoded += Hex[u8 & 0x0f]; } else { encoded += c; } } + return encoded; } @@ -219,9 +239,3 @@ std::string Url::GetAbsoluteUrl() const return GetUrlWithoutQuery(false) + _detail::FormatEncodedUrlQueryParameters(m_encodedQueryParameters); } - -const std::unordered_set Url::defaultNonUrlEncodeChars - = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', - 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', - 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '.', '_', '~'}; diff --git a/sdk/core/azure-core/src/http/user_agent.cpp b/sdk/core/azure-core/src/http/user_agent.cpp index 4ba98e95b..03ae3e8e7 100644 --- a/sdk/core/azure-core/src/http/user_agent.cpp +++ b/sdk/core/azure-core/src/http/user_agent.cpp @@ -13,7 +13,7 @@ #include "azure/core/http/policies/policy.hpp" #include "azure/core/internal/tracing/service_tracing.hpp" #include "azure/core/platform.hpp" -#include +#include #include #if defined(AZ_PLATFORM_WINDOWS) @@ -133,10 +133,10 @@ std::string GetOSVersion() std::string TrimString(std::string s) { - auto const isSpace = [](int c) { return !std::isspace(c); }; + auto const isNotSpace = [](char c) { return !std::isspace(c, std::locale::classic()); }; - s.erase(s.begin(), std::find_if(s.begin(), s.end(), isSpace)); - s.erase(std::find_if(s.rbegin(), s.rend(), isSpace).base(), s.end()); + s.erase(s.begin(), std::find_if(s.begin(), s.end(), isNotSpace)); + s.erase(std::find_if(s.rbegin(), s.rend(), isNotSpace).base(), s.end()); return s; } diff --git a/sdk/core/azure-core/src/strings.cpp b/sdk/core/azure-core/src/strings.cpp deleted file mode 100644 index 702ebd1b6..000000000 --- a/sdk/core/azure-core/src/strings.cpp +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// SPDX-License-Identifier: MIT - -#include "azure/core/internal/strings.hpp" - -#include - -namespace { -// The locale invariant case table is generated with the following program -// followed by clang-format. -#if 0 -// generate with -// cl /EHsc /W4 /WX .\casetable.cpp && .\casetable.exe -#include -#include -#include - -const int *PrintUpToLine(const int *first, const int *const last) { - if (first != last) { - printf("0x%02X,", *first); - for (ptrdiff_t idx = 1; ++first != last && idx < 8; ++idx) { - printf(" 0x%02X,", *first); - } - - puts(""); - } - - return first; -} - -int main() { - using namespace std; - int characters[256]; - iota(begin(characters), end(characters), 0); - for (ptrdiff_t idx = 'a'; idx <= 'z'; ++idx) { - characters[idx] = idx - ('a' - 'A'); - } - - const int *first = begin(characters); - const auto last = first + size(characters); - printf("{"); - while (first != last) { - first = PrintUpToLine(first, last); - } - printf("};"); -} - -#endif - -const unsigned char LocaleInvariantLowercaseTable[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, - 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, - 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, - 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, - 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, - 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, -}; -const unsigned char LocaleInvariantUppercaseTable[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, - 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, - 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, - 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, - 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, - 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, -}; -} // unnamed namespace - -namespace Azure { namespace Core { namespace _internal { - - unsigned char StringExtensions::ToLower(unsigned char const symbol) noexcept - { - return LocaleInvariantLowercaseTable[symbol]; - } - - std::string const StringExtensions::ToLower(const std::string& src) noexcept - { - auto result = std::string(src); - std::transform(result.begin(), result.end(), result.begin(), [](char const ch) { - return StringExtensions::ToLower(ch); - }); - return result; - } - - unsigned char StringExtensions::ToUpper(unsigned char const symbol) noexcept - { - return LocaleInvariantUppercaseTable[symbol]; - } - - std::string const StringExtensions::ToUpper(const std::string& src) noexcept - { - auto result = std::string(src); - std::transform(result.begin(), result.end(), result.begin(), [](char const ch) { - return StringExtensions::ToUpper(ch); - }); - return result; - } - - bool StringExtensions::LocaleInvariantCaseInsensitiveEqual( - const std::string& lhs, - const std::string& rhs) noexcept - { - return std::equal( - lhs.begin(), - lhs.end(), - rhs.begin(), - rhs.end(), - [](const char left, const char right) noexcept { - return LocaleInvariantLowercaseTable[static_cast(left)] - == LocaleInvariantLowercaseTable[static_cast(right)]; - }); - } - -}}} // namespace Azure::Core::_internal diff --git a/sdk/core/azure-core/src/tracing/tracing.cpp b/sdk/core/azure-core/src/tracing/tracing.cpp index d2c295503..4a4012ea2 100644 --- a/sdk/core/azure-core/src/tracing/tracing.cpp +++ b/sdk/core/azure-core/src/tracing/tracing.cpp @@ -5,7 +5,6 @@ #include "azure/core/http/policies/policy.hpp" #include "azure/core/internal/tracing/service_tracing.hpp" #include "azure/core/internal/tracing/tracing_impl.hpp" -#include #include namespace Azure { namespace Core { namespace Tracing { namespace _internal { diff --git a/sdk/core/azure-core/test/ut/string_test.cpp b/sdk/core/azure-core/test/ut/string_test.cpp index 91d277ff7..c3e710cd9 100644 --- a/sdk/core/azure-core/test/ut/string_test.cpp +++ b/sdk/core/azure-core/test/ut/string_test.cpp @@ -3,6 +3,8 @@ #include #include + +#include #include TEST(String, invariantCompare) @@ -23,18 +25,20 @@ TEST(String, invariantCompare) TEST(String, toLowerC) { using Azure::Core::_internal::StringExtensions; - for (unsigned char ch = 0; ch < 255; ch += 1) + for (unsigned i = 0; i <= 255; ++i) { - EXPECT_TRUE(StringExtensions::ToLower(ch) == std::tolower(ch)); + auto const c = static_cast(static_cast(i)); + EXPECT_TRUE(StringExtensions::ToLower(c) == std::tolower(c, std::locale::classic())); } } TEST(String, toUpperC) { using Azure::Core::_internal::StringExtensions; - for (unsigned char ch = 0; ch < 255; ch += 1) + for (unsigned i = 0; i <= 255; ++i) { - EXPECT_TRUE(StringExtensions::ToUpper(ch) == std::toupper(ch)); + auto const c = static_cast(static_cast(i)); + EXPECT_TRUE(StringExtensions::ToUpper(c) == std::toupper(c, std::locale::classic())); } } diff --git a/sdk/identity/azure-identity/src/azure_cli_credential.cpp b/sdk/identity/azure-identity/src/azure_cli_credential.cpp index 0a51b5c92..279d273d1 100644 --- a/sdk/identity/azure-identity/src/azure_cli_credential.cpp +++ b/sdk/identity/azure-identity/src/azure_cli_credential.cpp @@ -9,8 +9,8 @@ #include #include -#include #include +#include #include #include #include @@ -63,7 +63,7 @@ void ThrowIfNotSafeCmdLineInput(std::string const& input, std::string const& des break; default: - if (!std::isalnum(c)) + if (!std::isalnum(c, std::locale::classic())) { throw AuthenticationException( "AzureCliCredential: Unsafe command line input found in " + description + ": " diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/key_rotation_policy.cpp b/sdk/keyvault/azure-security-keyvault-keys/src/key_rotation_policy.cpp index 6b27ce1c7..dbeae29ba 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/src/key_rotation_policy.cpp +++ b/sdk/keyvault/azure-security-keyvault-keys/src/key_rotation_policy.cpp @@ -62,17 +62,16 @@ KeyRotationPolicy _detail::KeyRotationPolicySerializer::KeyRotationPolicyDeseria action[_detail::TriggerActionsValue], _detail::TBEActionsValue); - auto actionType = action[_detail::ActionActionsValue][TypeActionsValue].get(); - actionType = Azure::Core::_internal::StringExtensions::ToLower(actionType); + auto const actionType + = action[_detail::ActionActionsValue][TypeActionsValue].get(); - if (actionType - == Azure::Core::_internal::StringExtensions::ToLower(_detail::RotateActionsValue)) + if (Azure::Core::_internal::StringExtensions::LocaleInvariantCaseInsensitiveEqual( + actionType, _detail::RotateActionsValue)) { currentAction.Action = LifetimeActionType::Rotate; } - else if ( - actionType - == Azure::Core::_internal::StringExtensions::ToLower(_detail::NotifyActionsValue)) + else if (Azure::Core::_internal::StringExtensions::LocaleInvariantCaseInsensitiveEqual( + actionType, _detail::NotifyActionsValue)) { currentAction.Action = LifetimeActionType::Notify; } diff --git a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/rest_client.hpp b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/rest_client.hpp index 4ba1e301c..4d28cd840 100644 --- a/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/rest_client.hpp +++ b/sdk/storage/azure-storage-blobs/inc/azure/storage/blobs/rest_client.hpp @@ -13,12 +13,12 @@ #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -409,11 +409,7 @@ namespace Azure { namespace Storage { namespace Blobs { /** * A set of name-value pairs associated with this blob or blob container. */ - std::map< - std::string, - std::string, - Core::_internal::StringExtensions::CaseInsensitiveComparator> - Metadata; + Core::CaseInsensitiveMap Metadata; }; /** * @brief An Azure Storage container. @@ -648,11 +644,7 @@ namespace Azure { namespace Storage { namespace Blobs { /** * A set of name-value pair associated with this blob container. */ - std::map< - std::string, - std::string, - Core::_internal::StringExtensions::CaseInsensitiveComparator> - Metadata; + Core::CaseInsensitiveMap Metadata; /** * The ETag contains a value that you can use to perform operations conditionally. If the * request version is 2011-08-18 or newer, the ETag value will be in quotes. @@ -1289,11 +1281,7 @@ namespace Azure { namespace Storage { namespace Blobs { /** * A set of name-value pairs associated with this blob or blob container. */ - std::map< - std::string, - std::string, - Core::_internal::StringExtensions::CaseInsensitiveComparator> - Metadata; + Core::CaseInsensitiveMap Metadata; /** * User-defined tags for this blob. */ @@ -1480,11 +1468,7 @@ namespace Azure { namespace Storage { namespace Blobs { /** * A set of name-value pairs associated with this blob or blob container. */ - std::map< - std::string, - std::string, - Core::_internal::StringExtensions::CaseInsensitiveComparator> - Metadata; + Core::CaseInsensitiveMap Metadata; /** * The current sequence number for a page blob. */ @@ -1653,11 +1637,7 @@ namespace Azure { namespace Storage { namespace Blobs { /** * A set of name-value pair associated with this blob. */ - std::map< - std::string, - std::string, - Core::_internal::StringExtensions::CaseInsensitiveComparator> - Metadata; + Core::CaseInsensitiveMap Metadata; /** * Optional. Only valid when Object Replication is enabled for the storage container and on * the destination blob of the replication. diff --git a/sdk/storage/azure-storage-common/src/shared_key_policy.cpp b/sdk/storage/azure-storage-common/src/shared_key_policy.cpp index d0d6755ff..c6546502a 100644 --- a/sdk/storage/azure-storage-common/src/shared_key_policy.cpp +++ b/sdk/storage/azure-storage-common/src/shared_key_policy.cpp @@ -4,7 +4,6 @@ #include "azure/storage/common/internal/shared_key_policy.hpp" #include -#include #include #include @@ -32,7 +31,7 @@ namespace Azure { namespace Storage { namespace _internal { "If-Unmodified-Since", "Range"}) { - auto ite = headers.find(Azure::Core::_internal::StringExtensions::ToLower(headerName)); + auto ite = headers.find(headerName); if (ite != headers.end()) { if (headerName == "Content-Length" && ite->second == "0") diff --git a/sdk/storage/azure-storage-common/test/ut/test_base.cpp b/sdk/storage/azure-storage-common/test/ut/test_base.cpp index 2312e7567..7515c5a7b 100644 --- a/sdk/storage/azure-storage-common/test/ut/test_base.cpp +++ b/sdk/storage/azure-storage-common/test/ut/test_base.cpp @@ -4,7 +4,6 @@ #include "test_base.hpp" #include -#include #include #include #include diff --git a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/rest_client.hpp b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/rest_client.hpp index 371dc8e05..78c2d8b5f 100644 --- a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/rest_client.hpp +++ b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/rest_client.hpp @@ -13,12 +13,12 @@ #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -316,11 +316,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { /** * A set of name-value pairs associated with the share or file. */ - std::map< - std::string, - std::string, - Core::_internal::StringExtensions::CaseInsensitiveComparator> - Metadata; + Core::CaseInsensitiveMap Metadata; /** * Properties of a share. */ @@ -409,11 +405,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { /** * A set of name-value pairs that contain the user-defined metadata of the share. */ - std::map< - std::string, - std::string, - Core::_internal::StringExtensions::CaseInsensitiveComparator> - Metadata; + Core::CaseInsensitiveMap Metadata; /** * The ETag contains a value that you can use to perform operations conditionally, in quotes. */ @@ -886,11 +878,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { /** * A set of name-value pairs that contain metadata for the directory. */ - std::map< - std::string, - std::string, - Core::_internal::StringExtensions::CaseInsensitiveComparator> - Metadata; + Core::CaseInsensitiveMap Metadata; /** * The ETag contains a value that you can use to perform operations conditionally, in quotes. */ @@ -1290,11 +1278,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { /** * A set of name-value pairs associated with the share or file. */ - std::map< - std::string, - std::string, - Core::_internal::StringExtensions::CaseInsensitiveComparator> - Metadata; + Core::CaseInsensitiveMap Metadata; /** * String identifier for this copy operation. Use with Get File Properties to check the * status of this copy operation, or pass to Abort Copy File to abort a pending copy. @@ -1404,11 +1388,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { /** * A set of name-value pairs associated with this file as user-defined metadata. */ - std::map< - std::string, - std::string, - Core::_internal::StringExtensions::CaseInsensitiveComparator> - Metadata; + Core::CaseInsensitiveMap Metadata; /** * The size of the file in bytes. This header returns the value of the 'x-ms-content-length' * header that is stored with the file. diff --git a/sdk/storage/azure-storage-queues/inc/azure/storage/queues/rest_client.hpp b/sdk/storage/azure-storage-queues/inc/azure/storage/queues/rest_client.hpp index 44b42d452..c7347f8a1 100644 --- a/sdk/storage/azure-storage-queues/inc/azure/storage/queues/rest_client.hpp +++ b/sdk/storage/azure-storage-queues/inc/azure/storage/queues/rest_client.hpp @@ -12,10 +12,10 @@ #include #include +#include #include #include #include -#include #include #include #include @@ -211,11 +211,7 @@ namespace Azure { namespace Storage { namespace Queues { /** * A set of name-value pairs associated with this queue. */ - std::map< - std::string, - std::string, - Core::_internal::StringExtensions::CaseInsensitiveComparator> - Metadata; + Core::CaseInsensitiveMap Metadata; }; /** * @brief Include this parameter to specify that the queues' metadata be returned as part of the @@ -290,11 +286,7 @@ namespace Azure { namespace Storage { namespace Queues { */ struct QueueProperties final { - std::map< - std::string, - std::string, - Core::_internal::StringExtensions::CaseInsensitiveComparator> - Metadata; + Core::CaseInsensitiveMap Metadata; /** * The approximate number of messages in the queue. This number is not lower than the actual * number of messages in the queue, but could be higher.