From 36713d0dd58d51ae3ea915d40359fe4ae72eb8fb Mon Sep 17 00:00:00 2001 From: Robert Bennett Date: Tue, 20 Sep 2016 01:03:29 -0500 Subject: [PATCH 001/438] =?UTF-8?q?Enable=20TLS=201.1=20and=201.2=20?= =?UTF-8?q?=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By default only SSL3 and TLS1 are enabled in Windows 7 and Windows 8. By default only SSL3, TLS1.0, TLS1.1, and TLS1.2 are enabled in Windows 8.1 and Windows 10. https://msdn.microsoft.com/en-us/library/windows/desktop/aa384066 --- Release/src/http/client/http_client_winhttp.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 36f596b937..572803d2cc 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -427,6 +427,14 @@ class winhttp_client : public _http_client_communicator } } #endif + //Enable TLS 1.1 and 1.2 + HRESULT result(S_OK); + BOOL win32_result(FALSE); + + DWORD secure_protocols(WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2); + win32_result = ::WinHttpSetOption(m_hSession, WINHTTP_OPTION_SECURE_PROTOCOLS, &secure_protocols, sizeof(secure_protocols)); + if(FALSE == win32_result){ result = HRESULT_FROM_WIN32(::GetLastError()); } + // Register asynchronous callback. if(WINHTTP_INVALID_STATUS_CALLBACK == WinHttpSetStatusCallback( m_hSession, From 435d69cf60b149d01adf6e4095b0c4ed20e47a6a Mon Sep 17 00:00:00 2001 From: Jason Yang Date: Tue, 27 Sep 2016 15:26:22 +0800 Subject: [PATCH 002/438] Use index instead of iterator for utf16_to_utf8, performance improvement. --- Release/src/utilities/asyncrt_utils.cpp | 28 +++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index fac7787d49..fba168f81a 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -370,17 +370,19 @@ std::string __cdecl conversions::utf16_to_utf8(const utf16string &w) #else std::string dest; dest.reserve(w.size()); - for (auto src = w.begin(); src != w.end(); ++src) + + for (size_t index = 0; index < w.size(); ++index) { + auto src = w[index]; // Check for high surrogate. - if (*src >= H_SURROGATE_START && *src <= H_SURROGATE_END) + if (src >= H_SURROGATE_START && src <= H_SURROGATE_END) { - const auto highSurrogate = *src++; - if (src == w.end()) + const auto highSurrogate = w[++index]; + if (index == w.size()) { throw std::range_error("UTF-16 string is missing low surrogate"); } - const auto lowSurrogate = *src; + const auto lowSurrogate = src; if (lowSurrogate < L_SURROGATE_START || lowSurrogate > L_SURROGATE_END) { throw std::range_error("UTF-16 string has invalid low surrogate"); @@ -404,20 +406,20 @@ std::string __cdecl conversions::utf16_to_utf8(const utf16string &w) } else { - if (*src <= 0x7F) // single byte character + if (src <= 0x7F) // single byte character { - dest.push_back(static_cast(*src)); + dest.push_back(static_cast(src)); } - else if (*src <= 0x7FF) // 2 bytes needed (11 bits used) + else if (src <= 0x7FF) // 2 bytes needed (11 bits used) { - dest.push_back(char((*src >> 6) | 0xC0)); // leading 5 bits - dest.push_back(char((*src & LOW_6BITS) | BIT8)); // trailing 6 bits + dest.push_back(char((src >> 6) | 0xC0)); // leading 5 bits + dest.push_back(char((src & LOW_6BITS) | BIT8)); // trailing 6 bits } else // 3 bytes needed (16 bits used) { - dest.push_back(char((*src >> 12) | 0xE0)); // leading 4 bits - dest.push_back(char(((*src >> 6) & LOW_6BITS) | BIT8)); // middle 6 bits - dest.push_back(char((*src & LOW_6BITS) | BIT8)); // trailing 6 bits + dest.push_back(char((src >> 12) | 0xE0)); // leading 4 bits + dest.push_back(char(((src >> 6) & LOW_6BITS) | BIT8)); // middle 6 bits + dest.push_back(char((src & LOW_6BITS) | BIT8)); // trailing 6 bits } } } From b2aadf60d1ef563bb566c1360bf2af2f88c9885a Mon Sep 17 00:00:00 2001 From: Jason Yang Date: Tue, 27 Sep 2016 16:05:41 +0800 Subject: [PATCH 003/438] Fix the order of highSurrogate and lowSurrogate. --- Release/src/utilities/asyncrt_utils.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index fba168f81a..afa81729cd 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -377,12 +377,13 @@ std::string __cdecl conversions::utf16_to_utf8(const utf16string &w) // Check for high surrogate. if (src >= H_SURROGATE_START && src <= H_SURROGATE_END) { - const auto highSurrogate = w[++index]; + const auto highSurrogate = src; + ++index; if (index == w.size()) { throw std::range_error("UTF-16 string is missing low surrogate"); } - const auto lowSurrogate = src; + const auto lowSurrogate = w[index]; if (lowSurrogate < L_SURROGATE_START || lowSurrogate > L_SURROGATE_END) { throw std::range_error("UTF-16 string has invalid low surrogate"); From f9d32dfc2d61c30c765f8c70850e61e5026d044f Mon Sep 17 00:00:00 2001 From: Jason Yang Date: Thu, 29 Sep 2016 13:55:24 +0800 Subject: [PATCH 004/438] use pointers instead of operator[], extend to utf8_to_utf16 --- Release/src/utilities/asyncrt_utils.cpp | 274 ++++++++++++++++-------- 1 file changed, 186 insertions(+), 88 deletions(-) diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index afa81729cd..6565ba8d62 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -280,147 +280,245 @@ const std::error_category & __cdecl linux_category() #define H_SURROGATE_END 0xDBFF #define SURROGATE_PAIR_START 0x10000 -utf16string __cdecl conversions::utf8_to_utf16(const std::string &s) +inline size_t count_utf8_to_utf16(const std::string& s) { -#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS) - std::wstring_convert, utf16char> conversion; - return conversion.from_bytes(s); -#else - utf16string dest; - // Save repeated heap allocations, use less than source string size assuming some - // of the characters are not just ASCII and collapse. - dest.reserve(static_cast(static_cast(s.size()) * .70)); - - for (auto src = s.begin(); src != s.end(); ++src) + const size_t sSize = s.size(); + const char* const sData = s.data(); + size_t result{ sSize }; + for (size_t index = 0; index < sSize;) { - if ((*src & BIT8) == 0) // single byte character, 0x0 to 0x7F + const char c{ sData[index++] }; + if ((c & BIT8) == 0) { - dest.push_back(utf16string::value_type(*src)); + continue; } - else + + if ((c & BIT7) == 0) { - unsigned char numContBytes = 0; - uint32_t codePoint; - if ((*src & BIT7) == 0) + throw std::range_error("UTF-8 string character can never start with 10xxxxxx"); + } + else if ((c & BIT6) == 0) // 2 byte character, 0x80 to 0x7FF + { + if (index == sSize) { - throw std::range_error("UTF-8 string character can never start with 10xxxxxx"); + throw std::range_error("UTF-8 string is missing bytes in character"); } - else if ((*src & BIT6) == 0) // 2 byte character, 0x80 to 0x7FF + + const char c2{ sData[index++] }; + if ((c2 & 0xC0) != BIT8) { - codePoint = *src & LOW_5BITS; - numContBytes = 1; + throw std::range_error("UTF-8 continuation byte is missing leading byte"); } - else if ((*src & BIT5) == 0) // 3 byte character, 0x800 to 0xFFFF + + // can't require surrogates for 7FF + --result; + } + else if ((c & BIT5) == 0) // 3 byte character, 0x800 to 0xFFFF + { + if (sSize - index < 2) { - codePoint = *src & LOW_4BITS; - numContBytes = 2; + throw std::range_error("UTF-8 string is missing bytes in character"); } - else if ((*src & BIT4) == 0) // 4 byte character, 0x10000 to 0x10FFFF + + const char c2{ sData[index++] }; + const char c3{ sData[index++] }; + if (((c2 | c3) & 0xC0) != BIT8) { - codePoint = *src & LOW_3BITS; - numContBytes = 3; + throw std::range_error("UTF-8 continuation byte is missing leading byte"); } - else + + result -= 2; + } + else if ((c & BIT4) == 0) // 4 byte character, 0x10000 to 0x10FFFF + { + if (sSize - index < 3) { - throw std::range_error("UTF-8 string has invalid Unicode code point"); + throw std::range_error("UTF-8 string is missing bytes in character"); } - for (unsigned char i = 0; i < numContBytes; ++i) + const char c2{ sData[index++] }; + const char c3{ sData[index++] }; + const char c4{ sData[index++] }; + if (((c2 | c3 | c4) & 0xC0) != BIT8) { - if (++src == s.end()) + throw std::range_error("UTF-8 continuation byte is missing leading byte"); + } + + const uint32_t codePoint = ((c & LOW_3BITS) << 18) | ((c2 & LOW_6BITS) << 12) | ((c3 & LOW_6BITS) << 6) | (c4 & LOW_6BITS); + result -= (3 - (codePoint >= SURROGATE_PAIR_START)); + } + else + { + throw std::range_error("UTF-8 string has invalid Unicode code point"); + } + } + + return result; +} + +utf16string __cdecl conversions::utf8_to_utf16(const std::string &s) +{ +#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS) + std::wstring_convert, utf16char> conversion; + return conversion.from_bytes(s); +#else + // Save repeated heap allocations, use the length of resulting sequence. + const size_t srcSize = s.size(); + const std::string::value_type* const srcData = &s[0]; + 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]; + switch (src & 0xF0) + { + case 0xF0: // 4 byte character, 0x10000 to 0x10FFFF + { + const char c2{ srcData[++index] }; + const char c3{ srcData[++index] }; + const char c4{ srcData[++index] }; + uint32_t codePoint = ((src & LOW_3BITS) << 18) | ((c2 & LOW_6BITS) << 12) | ((c3 & LOW_6BITS) << 6) | (c4 & LOW_6BITS); + if (codePoint >= SURROGATE_PAIR_START) { - throw std::range_error("UTF-8 string is missing bytes in character"); + // In UTF-16 U+10000 to U+10FFFF are represented as two 16-bit code units, surrogate pairs. + // - 0x10000 is subtracted from the code point + // - high surrogate is 0xD800 added to the top ten bits + // - low surrogate is 0xDC00 added to the low ten bits + codePoint -= SURROGATE_PAIR_START; + destData[destIndex++] = static_cast((codePoint >> 10) | H_SURROGATE_START); + destData[destIndex++] = static_cast((codePoint & 0x3FF) | L_SURROGATE_START); } - if ((*src & BIT8) == 0 || (*src & BIT7) != 0) + else { - throw std::range_error("UTF-8 continuation byte is missing leading byte"); + // In UTF-16 U+0000 to U+D7FF and U+E000 to U+FFFF are represented exactly as the Unicode code point value. + // U+D800 to U+DFFF are not valid characters, for simplicity we assume they are not present but will encode + // them if encountered. + destData[destIndex++] = static_cast(codePoint); } - codePoint <<= 6; - codePoint |= *src & LOW_6BITS; } - - if (codePoint >= SURROGATE_PAIR_START) + break; + case 0xE0: // 3 byte character, 0x800 to 0xFFFF { - // In UTF-16 U+10000 to U+10FFFF are represented as two 16-bit code units, surrogate pairs. - // - 0x10000 is subtracted from the code point - // - high surrogate is 0xD800 added to the top ten bits - // - low surrogate is 0xDC00 added to the low ten bits - codePoint -= SURROGATE_PAIR_START; - dest.push_back(utf16string::value_type((codePoint >> 10) | H_SURROGATE_START)); - dest.push_back(utf16string::value_type((codePoint & 0x3FF) | L_SURROGATE_START)); + const char c2{ srcData[++index] }; + const char c3{ srcData[++index] }; + destData[destIndex++] = ((src & LOW_4BITS) << 12) | ((c2 & LOW_6BITS) << 6) | (c3 & LOW_6BITS); } - else + break; + case 0xD0: // 2 byte character, 0x80 to 0x7FF + case 0xC0: { - // In UTF-16 U+0000 to U+D7FF and U+E000 to U+FFFF are represented exactly as the Unicode code point value. - // U+D800 to U+DFFF are not valid characters, for simplicity we assume they are not present but will encode - // them if encountered. - dest.push_back(utf16string::value_type(codePoint)); + const char c2{ srcData[++index] }; + destData[destIndex++] = static_cast(((src & LOW_5BITS) << 6) | (c2 & LOW_6BITS)); } + break; + default: // single byte character, 0x0 to 0x7F + destData[destIndex++] = static_cast(src); } } return dest; #endif } -std::string __cdecl conversions::utf16_to_utf8(const utf16string &w) -{ - #if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS) - std::wstring_convert, utf16char> conversion; - return conversion.to_bytes(w); - #else - std::string dest; - dest.reserve(w.size()); - for (size_t index = 0; index < w.size(); ++index) +inline size_t count_utf16_to_utf8(const utf16string &w) +{ + const utf16string::value_type * const srcData = &w[0]; + const size_t srcSize = w.size(); + size_t destSize(srcSize); + for (size_t index = 0; index < srcSize; ++index) { - auto src = w[index]; + const utf16string::value_type ch(srcData[index]); + if (ch <= 0x7FF) + { + if (ch > 0x7F) // 2 bytes needed (11 bits used) + { + ++destSize; + } + } // Check for high surrogate. - if (src >= H_SURROGATE_START && src <= H_SURROGATE_END) + else if (ch >= H_SURROGATE_START && ch <= H_SURROGATE_END) // 4 bytes need using 21 bits { - const auto highSurrogate = src; - ++index; - if (index == w.size()) + ++index; + if (index == srcSize) { throw std::range_error("UTF-16 string is missing low surrogate"); } - const auto lowSurrogate = w[index]; + + const auto lowSurrogate = srcData[index]; if (lowSurrogate < L_SURROGATE_START || lowSurrogate > L_SURROGATE_END) { throw std::range_error("UTF-16 string has invalid low surrogate"); } - // To get from surrogate pair to Unicode code point: - // - subract 0xD800 from high surrogate, this forms top ten bits - // - subract 0xDC00 from low surrogate, this forms low ten bits - // - add 0x10000 - // Leaves a code point in U+10000 to U+10FFFF range. - uint32_t codePoint = highSurrogate - H_SURROGATE_START; - codePoint <<= 10; - codePoint |= lowSurrogate - L_SURROGATE_START; - codePoint += SURROGATE_PAIR_START; - - // 4 bytes need using 21 bits - dest.push_back(char((codePoint >> 18) | 0xF0)); // leading 3 bits - dest.push_back(char(((codePoint >> 12) & LOW_6BITS) | BIT8)); // next 6 bits - dest.push_back(char(((codePoint >> 6) & LOW_6BITS) | BIT8)); // next 6 bits - dest.push_back(char((codePoint & LOW_6BITS) | BIT8)); // trailing 6 bits + destSize += 2; } - else + else // 3 bytes needed (16 bits used) + { + destSize += 2; + } + } + + return destSize; +} + +std::string __cdecl conversions::utf16_to_utf8(const utf16string &w) +{ + #if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS) + std::wstring_convert, utf16char> conversion; + return conversion.to_bytes(w); + #else + const size_t srcSize = w.size(); + const utf16string::value_type* const srcData = &w[0]; + std::string dest(count_utf16_to_utf8(w), '\0'); + std::string::value_type* const destData = &dest[0]; + size_t destIndex(0); + + for (size_t index = 0; index < srcSize; ++index) + { + const utf16string::value_type src{ srcData[index] }; + if (src <= 0x7FF) { if (src <= 0x7F) // single byte character { - dest.push_back(static_cast(src)); + destData[destIndex++] = static_cast(src); } - else if (src <= 0x7FF) // 2 bytes needed (11 bits used) + else // 2 bytes needed (11 bits used) + { + destData[destIndex++] = static_cast(char((src >> 6) | 0xC0)); // leading 5 bits + destData[destIndex++] = static_cast(char((src & LOW_6BITS) | BIT8)); // trailing 6 bits + } + } + else + { + // Check for high surrogate. + if (src >= H_SURROGATE_START && src <= H_SURROGATE_END) { - dest.push_back(char((src >> 6) | 0xC0)); // leading 5 bits - dest.push_back(char((src & LOW_6BITS) | BIT8)); // trailing 6 bits + const auto highSurrogate{ src }; + const auto lowSurrogate{ srcData[++index] }; + + // To get from surrogate pair to Unicode code point: + // - subract 0xD800 from high surrogate, this forms top ten bits + // - subract 0xDC00 from low surrogate, this forms low ten bits + // - add 0x10000 + // Leaves a code point in U+10000 to U+10FFFF range. + uint32_t codePoint = highSurrogate - H_SURROGATE_START; + codePoint <<= 10; + codePoint |= lowSurrogate - L_SURROGATE_START; + codePoint += SURROGATE_PAIR_START; + + // 4 bytes need using 21 bits + destData[destIndex++] = static_cast((codePoint >> 18) | 0xF0); // leading 3 bits + destData[destIndex++] = static_cast(((codePoint >> 12) & LOW_6BITS) | BIT8); // next 6 bits + destData[destIndex++] = static_cast(((codePoint >> 6) & LOW_6BITS) | BIT8); // next 6 bits + destData[destIndex++] = static_cast((codePoint & LOW_6BITS) | BIT8); // trailing 6 bits } else // 3 bytes needed (16 bits used) { - dest.push_back(char((src >> 12) | 0xE0)); // leading 4 bits - dest.push_back(char(((src >> 6) & LOW_6BITS) | BIT8)); // middle 6 bits - dest.push_back(char((src & LOW_6BITS) | BIT8)); // trailing 6 bits + destData[destIndex++] = static_cast((src >> 12) | 0xE0); // leading 4 bits + destData[destIndex++] = static_cast(((src >> 6) & LOW_6BITS) | BIT8); // middle 6 bits + destData[destIndex++] = static_cast((src & LOW_6BITS) | BIT8); // trailing 6 bits } } } From 3be5716723471579ff94704281f261716c8f0b8a Mon Sep 17 00:00:00 2001 From: gwishnie Date: Mon, 5 Dec 2016 09:03:33 -0800 Subject: [PATCH 005/438] Enable IPv6 addresses to be resolved and specified as valid URI An IPv6 address must be enclosed in [] when in a URI (i.e. http://[:::::::]:80). This change allows the '[' and ']' as characters allowed as part of the authority so the underlying HTTP library can receive a resolved IPv6 address and utilize. The subsystem itself must support utilizing, this change only allows it to be treated as valid. --- Release/include/cpprest/details/uri_parser.h | 6 +-- Release/src/uri/uri_parser.cpp | 3 +- .../functional/uri/constructor_tests.cpp | 54 +++++++++++++++++++ 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/Release/include/cpprest/details/uri_parser.h b/Release/include/cpprest/details/uri_parser.h index 6cf023126c..e1b43db85c 100644 --- a/Release/include/cpprest/details/uri_parser.h +++ b/Release/include/cpprest/details/uri_parser.h @@ -143,13 +143,11 @@ namespace web { namespace details /// - The percent character ('%'), and thus any percent-endcoded octet /// - The sub-delimiters /// - ':' (colon) - /// - /// Note that we don't currently support: - /// - IPv6 addresses (requires '[]') + /// - IPv6 requires '[]' allowed for it to be valid URI and passed to underlying platform for IPv6 support /// inline bool is_authority_character(int c) { - return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == '@' || c == ':'; + return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == '@' || c == ':' || c == '[' || c == ']'; } /// diff --git a/Release/src/uri/uri_parser.cpp b/Release/src/uri/uri_parser.cpp index 5ea2b2437d..8198559b40 100644 --- a/Release/src/uri/uri_parser.cpp +++ b/Release/src/uri/uri_parser.cpp @@ -240,7 +240,8 @@ bool inner_parse( // or by EOS. The authority could be empty ('file:///C:\file_name.txt') for (;*p != _XPLATSTR('/') && *p != _XPLATSTR('?') && *p != _XPLATSTR('#') && *p != _XPLATSTR('\0'); p++) { - // We're NOT currently supporting IPv6, IPvFuture or username/password in authority + // We're NOT currently supporting IPvFuture or username/password in authority + // IPv6 as the host (i.e. http://[:::::::]) is allowed as valid URI and passed to subsystem for support. if (!is_authority_character(*p)) { return false; diff --git a/Release/tests/functional/uri/constructor_tests.cpp b/Release/tests/functional/uri/constructor_tests.cpp index 1411d385dd..a300c68f80 100644 --- a/Release/tests/functional/uri/constructor_tests.cpp +++ b/Release/tests/functional/uri/constructor_tests.cpp @@ -130,6 +130,60 @@ TEST(parsing_constructor_invalid) VERIFY_THROWS(uri(U("http://local/"host:345/")), uri_exception); } +// Tests a variety of different URIs using the examples in RFC 2732 +TEST(RFC_2732_examples_string) +{ + // The URI parser will make characters lower case + uri http1(U("http://[fedc:ba98:7654:3210:fedc:ba98:7654:3210]/index.html")); + VERIFY_ARE_EQUAL(U("http"), http1.scheme()); + VERIFY_ARE_EQUAL(U("[fedc:ba98:7654:3210:fedc:ba98:7654:3210]"), http1.host()); + VERIFY_ARE_EQUAL(80, http1.port()); + VERIFY_ARE_EQUAL(U("/index.html"), http1.path()); + VERIFY_ARE_EQUAL(U(""), http1.query()); + + uri http2(U("http://[1080::8:800:200c:417a]/index.html")); + VERIFY_ARE_EQUAL(U("http"), http2.scheme()); + VERIFY_ARE_EQUAL(U("[1080:0:0:0:8:800:200c:417a]"), http2.host()); + VERIFY_ARE_EQUAL(0, http2.port()); + VERIFY_ARE_EQUAL(U("/index.html"), http2.path()); + VERIFY_ARE_EQUAL(U(""), http2.query()); + + uri http3(U("https://[3ffe:2a00:100:7031::1]/")); + VERIFY_ARE_EQUAL(U("https"), http3.scheme()); + VERIFY_ARE_EQUAL(U("[3ffe:2a00:100:7031::1]"), http3.host()); + VERIFY_ARE_EQUAL(0, http3.port()); + VERIFY_ARE_EQUAL(U("/"), http3.path()); + VERIFY_ARE_EQUAL(U(""), http3.query()); + + uri http4(U("http://[::c009:505]/ipng")); + VERIFY_ARE_EQUAL(U("http"), http4.scheme()); + VERIFY_ARE_EQUAL(U("[::192.9.5.5]"), http4.host()); + VERIFY_ARE_EQUAL(0, http4.port()); + VERIFY_ARE_EQUAL(U("/ipng"), http4.path()); + VERIFY_ARE_EQUAL(U(""), http4.query()); + + uri http5(U("http://[1080::8:800:200c:417a]/foo")); + VERIFY_ARE_EQUAL(U("http"), http5.scheme()); + VERIFY_ARE_EQUAL(U("[1080::8:800:200c:417a]"), http5.host()); + VERIFY_ARE_EQUAL(0, http5.port()); + VERIFY_ARE_EQUAL(U("/foo"), http5.path()); + VERIFY_ARE_EQUAL(U(""), http5.query()); + + uri http6(U("http://[::ffff:8190:3426]/index.html")); + VERIFY_ARE_EQUAL(U("http"), http6.scheme()); + VERIFY_ARE_EQUAL(U("[::ffff:129.144.52.38]"), http6.host()); + VERIFY_ARE_EQUAL(80, http6.port()); + VERIFY_ARE_EQUAL(U("/index.html"), http6.path()); + VERIFY_ARE_EQUAL(U(""), http6.query()); + + uri http7(U("http://[2010:836b:4179::836b:4179]/")); + VERIFY_ARE_EQUAL(U("http"), http7.scheme()); + VERIFY_ARE_EQUAL(U("[2010:836b:4179::836b:4179]"), http7.host()); + VERIFY_ARE_EQUAL(0, http7.port()); + VERIFY_ARE_EQUAL(U("/"), http7.path()); + VERIFY_ARE_EQUAL(U(""), http7.query()); +} + // Tests a variety of different URIs using the examples in RFC 3986. TEST(RFC_3968_examples_string) { From d8950a67974a108cd2e664ecde2a75de5fe7592e Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 09:29:34 -0800 Subject: [PATCH 006/438] Refactor build around subcomponents to enable better dependency tracking. --- Release/CMakeLists.txt | 253 ++++++--------- Release/cmake/cpprest_find_boost.cmake | 40 +++ Release/cmake/cpprest_find_openssl.cmake | 62 ++++ Release/cmake/cpprest_find_websocketpp.cmake | 15 + Release/cmake/cpprest_find_zlib.cmake | 21 ++ Release/samples/BingRequest/CMakeLists.txt | 2 +- .../BlackJack/BlackJack_Client/CMakeLists.txt | 2 +- .../BlackJack/BlackJack_Server/CMakeLists.txt | 2 +- Release/samples/Oauth1Client/CMakeLists.txt | 2 +- Release/samples/Oauth2Client/CMakeLists.txt | 2 +- Release/samples/SearchFile/CMakeLists.txt | 2 +- Release/src/CMakeLists.txt | 306 ++++++++++++------ .../tests/common/TestRunner/CMakeLists.txt | 5 - .../tests/common/UnitTestpp/CMakeLists.txt | 12 +- .../functional/http/client/CMakeLists.txt | 5 + .../functional/http/utilities/CMakeLists.txt | 2 +- Release/tests/functional/json/CMakeLists.txt | 1 + .../tests/functional/streams/CMakeLists.txt | 6 + Release/tests/functional/uri/CMakeLists.txt | 1 + Release/tests/functional/utils/CMakeLists.txt | 5 + .../functional/websockets/CMakeLists.txt | 19 +- .../websockets/client/CMakeLists.txt | 1 + 22 files changed, 503 insertions(+), 263 deletions(-) create mode 100644 Release/cmake/cpprest_find_boost.cmake create mode 100644 Release/cmake/cpprest_find_openssl.cmake create mode 100644 Release/cmake/cpprest_find_websocketpp.cmake create mode 100644 Release/cmake/cpprest_find_zlib.cmake diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index cbb8d1ea83..7d6ee6a947 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -1,61 +1,93 @@ set(CMAKE_LEGACY_CYGWIN_WIN32 0) -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 2.8.12) +if(POLICY CMP0042) + cmake_policy(SET CMP0042 NEW) # use MACOSX_RPATH +endif() project(cpprest) enable_testing() +set(WERROR ON CACHE BOOL "Treat Warnings as Errors.") +set(CPPREST_EXCLUDE_WEBSOCKETS OFF CACHE BOOL "Exclude websockets functionality.") +set(CPPREST_EXCLUDE_COMPRESSION OFF CACHE BOOL "Exclude compression functionality.") +set(CPPREST_EXPORT_DIR lib/cpprest CACHE STRING "Directory to install CMake config files.") +set(CPPREST_EXPORT_NAME cpprest-config CACHE STRING "Name for CMake config file.") +set(CPPREST_INSTALL_HEADERS ON CACHE BOOL "Install header files.") + +if(IOS OR ANDROID) + set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries") +else() + set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries") +endif() + +if(IOS OR ANDROID OR WINDOWS_STORE OR WINDOWS_PHONE) + set(BUILD_TESTS OFF CACHE BOOL "Build tests.") + set(BUILD_SAMPLES OFF CACHE BOOL "Build sample applications.") +else() + set(BUILD_TESTS ON CACHE BOOL "Build tests.") + set(BUILD_SAMPLES ON CACHE BOOL "Build sample applications.") +endif() + +if(ANDROID) + set(Boost_USE_STATIC_LIBS ON CACHE BOOL "Link against boost statically.") +else() + set(Boost_USE_STATIC_LIBS OFF CACHE BOOL "Link against boost statically.") +endif() + +include(cmake/cpprest_find_boost.cmake) +include(cmake/cpprest_find_zlib.cmake) +include(cmake/cpprest_find_openssl.cmake) +include(cmake/cpprest_find_websocketpp.cmake) + +find_package(Threads REQUIRED) +if(THREADS_HAVE_PTHREAD_ARG) + add_compile_options(-pthread) +endif() +if(CMAKE_THREAD_LIBS_INIT) + link_libraries(${CMAKE_THREAD_LIBS_INIT}) +endif() + +# Internal component selection logic. This allows us to avoid duplicating platform logic in multiple places. +if(CPPREST_EXCLUDE_WEBSOCKETS) + set(CPPREST_WEBSOCKETS_IMPL none CACHE STRING "Internal use.") +endif() + +if(APPLE) # Note: also iOS + set(CPPREST_PPLX_IMPL apple CACHE STRING "Internal use.") + set(CPPREST_WEBSOCKETS_IMPL wspp CACHE STRING "Internal use.") + set(CPPREST_FILEIO_IMPL posix CACHE STRING "Internal use.") + set(CPPREST_HTTP_CLIENT_IMPL asio CACHE STRING "Internal use.") + set(CPPREST_HTTP_LISTENER_IMPL asio CACHE STRING "Internal use.") +elseif(UNIX AND NOT APPLE) # Note: also android + set(CPPREST_PPLX_IMPL linux CACHE STRING "Internal use.") + set(CPPREST_WEBSOCKETS_IMPL wspp CACHE STRING "Internal use.") + set(CPPREST_FILEIO_IMPL posix CACHE STRING "Internal use.") + set(CPPREST_HTTP_CLIENT_IMPL asio CACHE STRING "Internal use.") + set(CPPREST_HTTP_LISTENER_IMPL asio CACHE STRING "Internal use.") +elseif(WINDOWS_PHONE OR WINDOWS_STORE) + set(CPPREST_PPLX_IMPL win CACHE STRING "Internal use.") + set(CPPREST_WEBSOCKETS_IMPL winrt CACHE STRING "Internal use.") + set(CPPREST_FILEIO_IMPL winrt CACHE STRING "Internal use.") + set(CPPREST_HTTP_CLIENT_IMPL winrt CACHE STRING "Internal use.") + set(CPPREST_HTTP_LISTENER_IMPL none CACHE STRING "Internal use.") +elseif(WIN32) + set(CPPREST_PPLX_IMPL win CACHE STRING "Internal use.") + set(CPPREST_WEBSOCKETS_IMPL wspp CACHE STRING "Internal use.") + set(CPPREST_FILEIO_IMPL win32 CACHE STRING "Internal use.") + set(CPPREST_HTTP_CLIENT_IMPL winhttp CACHE STRING "Internal use.") + set(CPPREST_HTTP_LISTENER_IMPL httpsys CACHE STRING "Internal use.") +else() + message(FATAL_ERROR "Unknown platform. Cannot determine appropriate feature implementations.") +endif() + set(WARNINGS) set(ANDROID_STL_FLAGS) -option(WERROR "Threat Warnings as Errors" ON) -option(BUILD_TESTS "Build tests." ON) -option(CPPREST_EXCLUDE_WEBSOCKETS "Exclude websockets functionality." OFF) - # Platform (not compiler) specific settings if(IOS) - set(IOS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../Build_iOS") - set(Boost_FRAMEWORK "-F ${IOS_SOURCE_DIR} -framework boost") - set(Boost_INCLUDE_DIR "${IOS_SOURCE_DIR}/boost.framework/Headers") - - set(OPENSSL_FOUND 1) - set(OPENSSL_INCLUDE_DIR "${IOS_SOURCE_DIR}/openssl/include") - set(OPENSSL_LIBRARIES - "${IOS_SOURCE_DIR}/openssl/lib/libcrypto.a" - "${IOS_SOURCE_DIR}/openssl/lib/libssl.a" - ) - # The cxx_flags must be reset here, because the ios-cmake toolchain file unfortunately sets "-headerpad_max_install_names" which is not a valid clang flag. set(CMAKE_CXX_FLAGS "-fvisibility=hidden -fvisibility-inlines-hidden") - - set(BUILD_SHARED_LIBS OFF) - set(BUILD_SAMPLES OFF) elseif(ANDROID) - set(Boost_COMPILER "-clang") - set(Boost_USE_STATIC_LIBS ON) - if(ARM) - set(BOOST_ROOT "${CMAKE_BINARY_DIR}/../Boost-for-Android/build") - set(BOOST_LIBRARYDIR "${CMAKE_BINARY_DIR}/../Boost-for-Android/build/lib") - else() - set(BOOST_ROOT "${CMAKE_BINARY_DIR}/../Boost-for-Android-x86/build") - set(BOOST_LIBRARYDIR "${CMAKE_BINARY_DIR}/../Boost-for-Android-x86/build/lib") - endif() - find_host_package(Boost 1.55 EXACT REQUIRED COMPONENTS random system thread filesystem chrono atomic) - - set(OPENSSL_FOUND 1) - if(ARM) - set(OPENSSL_INCLUDE_DIR "${CMAKE_BINARY_DIR}/../openssl/armeabi-v7a/include") - set(OPENSSL_LIBRARIES - "${CMAKE_BINARY_DIR}/../openssl/armeabi-v7a/lib/libssl.a" - "${CMAKE_BINARY_DIR}/../openssl/armeabi-v7a/lib/libcrypto.a" - ) - else() - set(OPENSSL_INCLUDE_DIR "${CMAKE_BINARY_DIR}/../openssl/x86/include") - set(OPENSSL_LIBRARIES - "${CMAKE_BINARY_DIR}/../openssl/x86/lib/libssl.a" - "${CMAKE_BINARY_DIR}/../openssl/x86/lib/libcrypto.a" - ) - endif() - if(ARM) set(LIBCXX_STL "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a/thumb/libgnustl_static.a") else() @@ -72,41 +104,14 @@ elseif(ANDROID) -nodefaultlibs ) - option(BUILD_SHARED_LIBS "Build shared Libraries." OFF) - set(BUILD_SAMPLES OFF) + include_directories(SYSTEM + "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.8/include" + "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a/include" + "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.8/include/backward" + ) elseif(UNIX) # This includes OSX - find_package(Boost REQUIRED COMPONENTS random chrono system thread regex filesystem) - find_package(Threads REQUIRED) - if(APPLE AND NOT OPENSSL_ROOT_DIR) - # Prefer a homebrew version of OpenSSL over the one in /usr/lib - file(GLOB OPENSSL_ROOT_DIR /usr/local/Cellar/openssl/*) - # Prefer the latest (make the latest one first) - list(REVERSE OPENSSL_ROOT_DIR) - endif() - # This should prevent linking against the system provided 0.9.8y - set(_OPENSSL_VERSION "") - find_package(OpenSSL 1.0.0 REQUIRED) - - option(BUILD_SHARED_LIBS "Build shared Libraries." ON) - - # Prefer the homebrew version of zlib - find_library(ZLIB_LIBRARIES NAMES libz.a PATHS /usr/local/Cellar/zlib/1.2.8/lib NO_DEFAULT_PATH) - find_path(ZLIB_INCLUDE_DIRS NAMES zlib.h PATHS /usr/local/Cellar/zlib/1.2.8/include NO_DEFAULT_PATH) - - if(NOT ZLIB_LIBRARIES OR NOT ZLIB_INCLUDE_DIRS) - find_package(ZLIB) - if(NOT ZLIB_FOUND) - option(CPPREST_EXCLUDE_COMPRESSION "Exclude compression functionality." ON) - endif() - endif() - - option(BUILD_SAMPLES "Build samples." ON) elseif(WIN32) - option(BUILD_SHARED_LIBS "Build shared Libraries." ON) - option(BUILD_SAMPLES "Build samples." ON) - option(Boost_USE_STATIC_LIBS ON) - - add_definitions(-DUNICODE -D_UNICODE) + add_definitions(-DUNICODE -D_UNICODE -D_WIN32_WINNT=0x0600) if(NOT BUILD_SHARED_LIBS) # This causes cmake to not link the test libraries separately, but instead hold onto their object files. @@ -116,55 +121,37 @@ elseif(WIN32) set(Casablanca_DEFINITIONS "" CACHE INTERNAL "Definitions for consume casablanca library") endif() add_definitions(${Casablanca_DEFINITIONS} -D_WINSOCK_DEPRECATED_NO_WARNINGS -DWIN32) - if (NOT CPPREST_EXCLUDE_WEBSOCKETS AND NOT WINDOWS_STORE) - find_package(ZLIB REQUIRED) - find_package(OpenSSL REQUIRED) - find_package(Boost REQUIRED COMPONENTS regex system date_time) - endif() else() message(FATAL_ERROR "-- Unsupported Build Platform.") endif() -option(CASA_INSTALL_HEADERS "Install header files." ON) -if(CASA_INSTALL_HEADERS) - file(GLOB CASA_HEADERS_CPPREST include/cpprest/*.hpp include/cpprest/*.h include/cpprest/*.dat) - install(FILES ${CASA_HEADERS_CPPREST} DESTINATION include/cpprest) - file(GLOB CASA_HEADERS_PPLX include/pplx/*.hpp include/pplx/*.h) - install(FILES ${CASA_HEADERS_PPLX} DESTINATION include/pplx) - file(GLOB CASA_HEADERS_DETAILS include/cpprest/details/*.hpp include/cpprest/details/*.h include/cpprest/details/*.dat) - install(FILES ${CASA_HEADERS_DETAILS} DESTINATION include/cpprest/details) -endif() - # Compiler (not platform) specific settings -if(ANDROID) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-strict-aliasing") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-pedantic") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-attributes -Wno-pointer-arith") - include_directories(SYSTEM - "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.8/include" - "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a/include" - "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.8/include/backward" - ) -elseif((CMAKE_CXX_COMPILER_ID MATCHES "Clang") OR IOS) +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR IOS) message("-- Setting clang options") - set(WARNINGS "-Wall -Wextra -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls") - set(OSX_SUPPRESSIONS "-Wno-overloaded-virtual -Wno-sign-conversion -Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-char-subscripts -Wno-switch -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated -Wno-unused-value -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-unused-function -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-reorder -Wno-unused-local-typedefs") - set(WARNINGS "${WARNINGS} ${OSX_SUPPRESSIONS}") + if(ANDROID) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-pedantic") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-attributes -Wno-pointer-arith") + else() + set(WARNINGS -Wall -Wextra -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls) + set(OSX_SUPPRESSIONS -Wno-overloaded-virtual -Wno-sign-conversion -Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-char-subscripts -Wno-switch -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated -Wno-unused-value -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-unused-function -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-reorder -Wno-unused-local-typedefs) + set(WARNINGS ${WARNINGS} ${OSX_SUPPRESSIONS}) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -Wno-return-type-c-linkage -Wno-unneeded-internal-declaration") - set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") - set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -Wno-return-type-c-linkage -Wno-unneeded-internal-declaration") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11") + endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-strict-aliasing") + elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") message("-- Setting gcc options") - set(WARNINGS "-Wall -Wextra -Wunused-parameter -Wcast-align -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls -Wunreachable-code") - + set(WARNINGS -Wall -Wextra -Wunused-parameter -Wcast-align -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls -Wunreachable-code) set(LD_FLAGS "${LD_FLAGS} -Wl,-z,defs") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-strict-aliasing") + elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") message("-- Setting msvc options") set(WARNINGS) @@ -178,10 +165,6 @@ else() message("CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}") endif() -if (CPPREST_EXCLUDE_WEBSOCKETS) - add_definitions(-DCPPREST_EXCLUDE_WEBSOCKETS=1) -endif() - # Reconfigure final output directory set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Binaries) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Binaries) @@ -190,40 +173,12 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Binaries) # These settings can be used by the test targets set(Casablanca_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include) set(Casablanca_SYSTEM_INCLUDE_DIRS) -if (NOT CPPREST_EXCLUDE_WEBSOCKETS) - find_path(WEBSOCKETPP_CONFIG websocketpp-config.cmake - HINTS /usr/lib/cmake/websocketpp) - find_path(WEBSOCKETPP_CONFIG_VERSION websocketpp-configVersion.cmake - HINTS /usr/lib/cmake/websocketpp) - if(WEBSOCKETPP_CONFIG AND WEBSOCKETPP_CONFIG_VERSION) - include(${WEBSOCKETPP_CONFIG}/websocketpp-config.cmake) - include(${WEBSOCKETPP_CONFIG}/websocketpp-configVersion.cmake) - message("-- Found websocketpp version " ${PACKAGE_VERSION} " on system") - list(APPEND Casablanca_SYSTEM_INCLUDE_DIRS ${Boost_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ${WEBSOCKETPP_INCLUDE_DIR}) - else(WEBSOCKETPP_CONFIG AND WEBSOCKETPP_CONFIG_VERSION) - list(APPEND Casablanca_SYSTEM_INCLUDE_DIRS ${Boost_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/libs/websocketpp) - message("-- websocketpp not found, using the embedded version") - endif(WEBSOCKETPP_CONFIG AND WEBSOCKETPP_CONFIG_VERSION) - - INCLUDE(CheckCXXSourceCompiles) - set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}") - set(CMAKE_REQUIRED_LIBRARIES "${OPENSSL_LIBRARIES}") - CHECK_CXX_SOURCE_COMPILES(" - #include - int main() - { - ::SSL_COMP_free_compression_methods(); - } - " _SSL_LEAK_SUPPRESS_AVAILABLE) - if (NOT _SSL_LEAK_SUPPRESS_AVAILABLE) - # libressl doesn't ship with the cleanup method being used in ws_client_wspp - add_definitions(-DCPPREST_NO_SSL_LEAK_SUPPRESS) - endif() -endif() - set(Casablanca_LIBRARY cpprest) -set(Casablanca_LIBRARIES cpprest ${Boost_LIBRARIES} ${ZLIB_LIBRARIES}) -set(Casablanca_LIBRARIES ${Casablanca_LIBRARIES} PARENT_SCOPE) +set(Casablanca_LIBRARIES cpprest) +get_directory_property(PARENT_DIR PARENT_DIRECTORY) +if(NOT PARENT_DIR STREQUAL "") + set(Casablanca_LIBRARIES ${Casablanca_LIBRARIES} PARENT_SCOPE) +endif() # Everything in the project needs access to the casablanca include directories include_directories( ${Casablanca_INCLUDE_DIRS}) @@ -238,7 +193,7 @@ function(add_casablanca_test NAME SOURCES_VAR) httptest_utilities common_utilities unittestpp - ${Casablanca_LIBRARIES} + cpprest ${ANDROID_STL_FLAGS} ) if (BUILD_SHARED_LIBS) diff --git a/Release/cmake/cpprest_find_boost.cmake b/Release/cmake/cpprest_find_boost.cmake new file mode 100644 index 0000000000..e1c8289c6c --- /dev/null +++ b/Release/cmake/cpprest_find_boost.cmake @@ -0,0 +1,40 @@ +function(cpprest_find_boost) + if(Boost_FOUND) + return() + endif() + + if(IOS) + set(IOS_SOURCE_DIR "${PROJECT_SOURCE_DIR}/../Build_iOS") + set(Boost_FOUND 1 CACHE INTERNAL "") + set(Boost_FRAMEWORK "-F ${IOS_SOURCE_DIR} -framework boost" CACHE INTERNAL "") + set(Boost_INCLUDE_DIR "$" CACHE INTERNAL "") + elseif(ANDROID) + set(Boost_COMPILER "-clang") + if(ARM) + set(BOOST_ROOT "${CMAKE_BINARY_DIR}/../Boost-for-Android/build" CACHE INTERNAL "") + set(BOOST_LIBRARYDIR "${CMAKE_BINARY_DIR}/../Boost-for-Android/build/lib" CACHE INTERNAL "") + else() + set(BOOST_ROOT "${CMAKE_BINARY_DIR}/../Boost-for-Android-x86/build" CACHE INTERNAL "") + set(BOOST_LIBRARYDIR "${CMAKE_BINARY_DIR}/../Boost-for-Android-x86/build/lib" CACHE INTERNAL "") + endif() + find_host_package(Boost 1.55 EXACT REQUIRED COMPONENTS random system thread filesystem chrono atomic) + elseif(UNIX) + find_package(Boost REQUIRED COMPONENTS random system thread filesystem chrono atomic date_time regex) + else() + find_package(Boost REQUIRED COMPONENTS system date_time regex) + endif() + + set(Boost_FOUND 1 CACHE INTERNAL "") + set(Boost_INCLUDE_DIR ${Boost_INCLUDE_DIR} CACHE INTERNAL "") + set(Boost_LIBRARIES + ${Boost_SYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_ATOMIC_LIBRARY} + ${Boost_CHRONO_LIBRARY} + ${Boost_RANDOM_LIBRARY} + ${Boost_REGEX_LIBRARY} + ${Boost_DATE_TIME_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${BOOST_FRAMEWORK} + CACHE INTERNAL "") + endfunction() \ No newline at end of file diff --git a/Release/cmake/cpprest_find_openssl.cmake b/Release/cmake/cpprest_find_openssl.cmake new file mode 100644 index 0000000000..8ae2db6640 --- /dev/null +++ b/Release/cmake/cpprest_find_openssl.cmake @@ -0,0 +1,62 @@ +function(cpprest_find_openssl) + if(OPENSSL_FOUND) + return() + endif() + + if(IOS) + set(IOS_SOURCE_DIR "${PROJECT_SOURCE_DIR}/../Build_iOS") + set(OPENSSL_FOUND 1 CACHE INTERNAL "") + set(OPENSSL_INCLUDE_DIR "$" CACHE INTERNAL "") + set(OPENSSL_LIBRARIES + "${IOS_SOURCE_DIR}/openssl/lib/libcrypto.a" + "${IOS_SOURCE_DIR}/openssl/lib/libssl.a" + CACHE INTERNAL "" + ) + set(_SSL_LEAK_SUPPRESS_AVAILABLE ON CACHE INTERNAL "") + return() + elseif(ANDROID) + set(OPENSSL_FOUND 1 CACHE INTERNAL "") + if(ARM) + set(OPENSSL_INCLUDE_DIR "$" CACHE INTERNAL "") + set(OPENSSL_LIBRARIES + "${CMAKE_BINARY_DIR}/../openssl/armeabi-v7a/lib/libssl.a" + "${CMAKE_BINARY_DIR}/../openssl/armeabi-v7a/lib/libcrypto.a" + CACHE INTERNAL "" + ) + else() + set(OPENSSL_INCLUDE_DIR "$" CACHE INTERNAL "") + set(OPENSSL_LIBRARIES + "${CMAKE_BINARY_DIR}/../openssl/x86/lib/libssl.a" + "${CMAKE_BINARY_DIR}/../openssl/x86/lib/libcrypto.a" + CACHE INTERNAL "" + ) + endif() + elseif(APPLE) + if(NOT DEFINED OPENSSL_ROOT_DIR) + # Prefer a homebrew version of OpenSSL over the one in /usr/lib + file(GLOB OPENSSL_ROOT_DIR /usr/local/Cellar/openssl/*) + # Prefer the latest (make the latest one first) + list(REVERSE OPENSSL_ROOT_DIR) + endif() + # This should prevent linking against the system provided 0.9.8y + set(_OPENSSL_VERSION "") + find_package(OpenSSL 1.0.0 REQUIRED) + else() + find_package(OpenSSL 1.0.0 REQUIRED) + endif() + + set(OPENSSL_FOUND 1 CACHE INTERNAL "") + set(OPENSSL_INCLUDE_DIR ${OPENSSL_INCLUDE_DIR} CACHE INTERNAL "") + set(OPENSSL_LIBRARIES ${OPENSSL_LIBRARIES} CACHE INTERNAL "") + + INCLUDE(CheckCXXSourceCompiles) + set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}") + set(CMAKE_REQUIRED_LIBRARIES "${OPENSSL_LIBRARIES}") + CHECK_CXX_SOURCE_COMPILES(" + #include + int main() + { + ::SSL_COMP_free_compression_methods(); + } + " _SSL_LEAK_SUPPRESS_AVAILABLE) +endfunction() \ No newline at end of file diff --git a/Release/cmake/cpprest_find_websocketpp.cmake b/Release/cmake/cpprest_find_websocketpp.cmake new file mode 100644 index 0000000000..165aed2aba --- /dev/null +++ b/Release/cmake/cpprest_find_websocketpp.cmake @@ -0,0 +1,15 @@ +function(cpprest_find_websocketpp) + if(WEBSOCKETPP_FOUND) + return() + endif() + + find_package(WEBSOCKETPP CONFIG QUIET) + if(WEBSOCKETPP_FOUND) + message("-- Found websocketpp version " ${WEBSOCKETPP_VERSION} " on system") + set(WEBSOCKETPP_INCLUDE_DIR ${WEBSOCKETPP_INCLUDE_DIR} CACHE INTERNAL "") + else() + message("-- websocketpp not found, using the embedded version") + set(WEBSOCKETPP_FOUND 1 CACHE INTERNAL "" FORCE) + set(WEBSOCKETPP_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/libs/websocketpp CACHE INTERNAL "") + endif() +endfunction() \ No newline at end of file diff --git a/Release/cmake/cpprest_find_zlib.cmake b/Release/cmake/cpprest_find_zlib.cmake new file mode 100644 index 0000000000..1b5302566c --- /dev/null +++ b/Release/cmake/cpprest_find_zlib.cmake @@ -0,0 +1,21 @@ +function(cpprest_find_zlib) + if(ZLIB_FOUND) + return() + endif() + + if(APPLE AND NOT IOS) + # Prefer the homebrew version of zlib + find_library(ZLIB_LIBRARIES NAMES libz.a PATHS /usr/local/Cellar/zlib/1.2.8/lib NO_DEFAULT_PATH) + find_path(ZLIB_INCLUDE_DIRS NAMES zlib.h PATHS /usr/local/Cellar/zlib/1.2.8/include NO_DEFAULT_PATH) + + if(NOT ZLIB_LIBRARIES OR NOT ZLIB_INCLUDE_DIRS) + find_package(ZLIB REQUIRED) + endif() + else() + find_package(ZLIB REQUIRED) + endif() + + set(ZLIB_FOUND 1 CACHE INTERNAL "") + set(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIRS} CACHE INTERNAL "") + set(ZLIB_LIBRARIES ${ZLIB_LIBRARIES} CACHE INTERNAL "") +endfunction() \ No newline at end of file diff --git a/Release/samples/BingRequest/CMakeLists.txt b/Release/samples/BingRequest/CMakeLists.txt index 261078cb76..41dc733f62 100644 --- a/Release/samples/BingRequest/CMakeLists.txt +++ b/Release/samples/BingRequest/CMakeLists.txt @@ -1,4 +1,4 @@ if (NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) add_executable(BingRequest bingrequest.cpp) - target_link_libraries(BingRequest ${Casablanca_LIBRARIES}) + target_link_libraries(BingRequest cpprest) endif() \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_Client/CMakeLists.txt b/Release/samples/BlackJack/BlackJack_Client/CMakeLists.txt index 314046f4f4..f884ca8f8d 100644 --- a/Release/samples/BlackJack/BlackJack_Client/CMakeLists.txt +++ b/Release/samples/BlackJack/BlackJack_Client/CMakeLists.txt @@ -7,4 +7,4 @@ add_executable(blackjackclient stdafx.cpp ) -target_link_libraries(blackjackclient ${Casablanca_LIBRARIES}) +target_link_libraries(blackjackclient cpprest) diff --git a/Release/samples/BlackJack/BlackJack_Server/CMakeLists.txt b/Release/samples/BlackJack/BlackJack_Server/CMakeLists.txt index d0696c4c9e..c5b2fec0af 100644 --- a/Release/samples/BlackJack/BlackJack_Server/CMakeLists.txt +++ b/Release/samples/BlackJack/BlackJack_Server/CMakeLists.txt @@ -9,4 +9,4 @@ add_executable(blackjackserver Table.cpp ) -target_link_libraries(blackjackserver ${Casablanca_LIBRARIES}) +target_link_libraries(blackjackserver cpprest) diff --git a/Release/samples/Oauth1Client/CMakeLists.txt b/Release/samples/Oauth1Client/CMakeLists.txt index ee8c82f2dc..4630cba8fe 100644 --- a/Release/samples/Oauth1Client/CMakeLists.txt +++ b/Release/samples/Oauth1Client/CMakeLists.txt @@ -4,5 +4,5 @@ if (NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) stdafx.cpp ) - target_link_libraries(oauth1client ${Casablanca_LIBRARIES}) + target_link_libraries(oauth1client cpprest) endif() \ No newline at end of file diff --git a/Release/samples/Oauth2Client/CMakeLists.txt b/Release/samples/Oauth2Client/CMakeLists.txt index 212afb2001..8c3bdbc118 100644 --- a/Release/samples/Oauth2Client/CMakeLists.txt +++ b/Release/samples/Oauth2Client/CMakeLists.txt @@ -4,5 +4,5 @@ if (NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) stdafx.cpp ) - target_link_libraries(oauth2client ${Casablanca_LIBRARIES}) + target_link_libraries(oauth2client cpprest) endif() \ No newline at end of file diff --git a/Release/samples/SearchFile/CMakeLists.txt b/Release/samples/SearchFile/CMakeLists.txt index d933df6781..7dd46a4cd0 100644 --- a/Release/samples/SearchFile/CMakeLists.txt +++ b/Release/samples/SearchFile/CMakeLists.txt @@ -1,4 +1,4 @@ if (NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) add_executable(SearchFile searchfile.cpp) - target_link_libraries(SearchFile ${Casablanca_LIBRARIES}) + target_link_libraries(SearchFile cpprest) endif() diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 23d0640074..482b196c43 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -1,20 +1,17 @@ -include_directories(../include pch) -if (NOT CPPREST_EXCLUDE_WEBSOCKETS OR NOT WIN32) - include_directories(SYSTEM ${Boost_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIRS}) -endif() - -add_definitions(${WARNINGS}) - -file(GLOB SOURCES_CPPREST "../include/cpprest/*.h") -file(GLOB SOURCES_PPLX "../include/pplx/*.h") -file(GLOB SOURCES_DETAILS "../include/cpprest/details/*.h") -source_group("Header Files\\cpprest" FILES ${SOURCES_CPPREST}) -source_group("Header Files\\pplx" FILES ${SOURCES_PPLX}) -source_group("Header Files\\cpprest\\details" FILES ${SOURCES_DETAILS}) -set(SOURCES_COMMON - ${SOURCES_CPPREST} - ${SOURCES_PPLX} - ${SOURCES_DETAILS} +cmake_policy(SET CMP0022 NEW) + +file(GLOB HEADERS_CPPREST "../include/cpprest/*.h" "../include/cpprest/*.hpp" "../include/cpprest/*.dat") +file(GLOB HEADERS_PPLX "../include/pplx/*.h" "../include/pplx/*.hpp") +file(GLOB HEADERS_DETAILS "../include/cpprest/details/*.h" "../include/pplx/*.hpp" "../include/pplx/*.dat") +source_group("Header Files\\cpprest" FILES ${HEADERS_CPPREST}) +source_group("Header Files\\pplx" FILES ${HEADERS_PPLX}) +source_group("Header Files\\cpprest\\details" FILES ${HEADERS_DETAILS}) + +set(SOURCES + ${HEADERS_CPPREST} + ${HEADERS_PPLX} + ${HEADERS_DETAILS} + pch/stdafx.h http/client/http_client.cpp http/client/http_client_msg.cpp http/client/http_client_impl.h @@ -36,68 +33,72 @@ set(SOURCES_COMMON utilities/asyncrt_utils.cpp utilities/base64.cpp utilities/web_utilities.cpp - websockets/client/ws_msg.cpp - websockets/client/ws_client.cpp ) -# THE ORDER OF FILES IS VERY /VERY/ IMPORTANT -if(UNIX) - set(SOURCES - ${SOURCES_COMMON} - streams/fileio_posix.cpp - pplx/threadpool.cpp - http/client/http_client_asio.cpp - http/listener/http_server_asio.cpp +## Sub-component sources +# Websockets component +if(CPPREST_WEBSOCKETS_IMPL STREQUAL "none") +elseif(CPPREST_WEBSOCKETS_IMPL STREQUAL "winrt") + list(APPEND SOURCES + websockets/client/ws_msg.cpp + websockets/client/ws_client.cpp + websockets/client/ws_client_winrt.cpp ) - if (NOT CPPREST_EXCLUDE_WEBSOCKETS) - list(APPEND SOURCES websockets/client/ws_client_wspp.cpp) - endif() - if(APPLE) - list(APPEND SOURCES - pplx/pplxapple.cpp - ) - find_library(COREFOUNDATION CoreFoundation "/") - find_library(SECURITY Security "/") - set(EXTRALINKS ${COREFOUNDATION} ${SECURITY}) - elseif(ANDROID) - list(APPEND SOURCES - pplx/pplxlinux.cpp - ) - else() - list(APPEND SOURCES pplx/pplxlinux.cpp) - endif() +elseif(CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") + list(APPEND SOURCES + websockets/client/ws_msg.cpp + websockets/client/ws_client.cpp + websockets/client/ws_client_wspp.cpp + ) +endif() - if(WERROR) - add_compile_options(-Werror) - endif() - add_compile_options(-pedantic) -elseif(WIN32) - set(SOURCES ${SOURCES_COMMON} +# Compression component +# No sources to add + +# PPLX component +if(CPPREST_PPLX_IMPL STREQUAL "apple") + list(APPEND SOURCES + pplx/threadpool.cpp + pplx/pplxapple.cpp + ) +elseif(CPPREST_PPLX_IMPL STREQUAL "linux") + list(APPEND SOURCES + pplx/threadpool.cpp + pplx/pplxlinux.cpp + ) +elseif(CPPREST_PPLX_IMPL STREQUAL "win") + list(APPEND SOURCES + pplx/threadpool.cpp pplx/pplxwin.cpp ) - if (WINDOWS_PHONE OR WINDOWS_STORE) - list(APPEND SOURCES - http/client/http_client_winrt.cpp - streams/fileio_winrt.cpp - websockets/client/ws_client_winrt.cpp - ) - else() - list(APPEND SOURCES - http/client/http_client_winhttp.cpp - http/listener/http_server_httpsys.cpp - streams/fileio_win32.cpp - ) - if (NOT CPPREST_EXCLUDE_WEBSOCKETS) - list(APPEND SOURCES websockets/client/ws_client_wspp.cpp) - endif() - set(EXTRALINKS - bcrypt.lib - crypt32.lib - httpapi.lib - Winhttp.lib - ) - endif() - add_compile_options(/Yustdafx.h /Zm200) +endif() + +# Http client component +if(CPPREST_HTTP_CLIENT_IMPL STREQUAL "asio") + list(APPEND SOURCES http/client/http_client_asio.cpp) +elseif(CPPREST_HTTP_CLIENT_IMPL STREQUAL "winhttp") + list(APPEND SOURCES http/client/http_client_winhttp.cpp) +elseif(CPPREST_HTTP_CLIENT_IMPL STREQUAL "winrt") + list(APPEND SOURCES http/client/http_client_winrt.cpp) +endif() + +# fileio streams component +if(CPPREST_FILEIO_IMPL STREQUAL "win32") + list(APPEND SOURCES streams/fileio_win32.cpp) +elseif(CPPREST_FILEIO_IMPL STREQUAL "winrt") + list(APPEND SOURCES streams/fileio_winrt.cpp) +elseif(CPPREST_FILEIO_IMPL STREQUAL "posix") + list(APPEND SOURCES streams/fileio_posix.cpp) +endif() + +# http listener component +if(CPPREST_HTTP_LISTENER_IMPL STREQUAL "asio") + list(APPEND SOURCES http/listener/http_server_asio.cpp) +elseif(CPPREST_HTTP_LISTENER_IMPL STREQUAL "httpsys") + list(APPEND SOURCES http/listener/http_server_httpsys.cpp) +endif() + +if(MSVC) set_source_files_properties(pch/stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") if (NOT ${CMAKE_GENERATOR} MATCHES "Visual Studio .*") @@ -105,36 +106,140 @@ elseif(WIN32) set_property(SOURCE ${SOURCES} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") endif() - list(APPEND SOURCES pch/stdafx.cpp pch/stdafx.h) + add_library(cpprest ${SOURCES} pch/stdafx.cpp) + target_compile_options(cpprest PRIVATE /Yustdafx.h /Zm200) +else() + add_library(cpprest ${SOURCES}) +endif() + +target_include_directories(cpprest + PUBLIC + $ $ + PRIVATE + pch +) - if (BUILD_SHARED_LIBS) - add_definitions(-D_ASYNCRT_EXPORT -D_PPLX_EXPORT -D_USRDLL) +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") + if(WERROR) + target_compile_options(cpprest PRIVATE -Werror) + endif() + target_compile_options(cpprest PRIVATE -pedantic) +elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + if(WERROR) + target_compile_options(cpprest PRIVATE /WX) endif() endif() -add_library(cpprest ${SOURCES}) +if (BUILD_SHARED_LIBS AND WIN32) + target_compile_definitions(cpprest PRIVATE -D_ASYNCRT_EXPORT -D_PPLX_EXPORT -D_USRDLL) +endif() + +target_compile_options(cpprest PRIVATE ${WARNINGS}) -target_include_directories(cpprest - INTERFACE $ - PUBLIC $ +set(CPPREST_USES_BOOST OFF) +set(CPPREST_USES_OPENSSL OFF) +set(CPPREST_USES_ZLIB OFF) +set(CPPREST_USES_WEBSOCKETPP OFF) + +if (WIN32 AND NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) + target_link_libraries(cpprest PRIVATE + bcrypt.lib + crypt32.lib ) +endif() -target_link_libraries(cpprest - ${CMAKE_THREAD_LIBS_INIT} - ${Boost_SYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_ATOMIC_LIBRARY} - ${Boost_CHRONO_LIBRARY} - ${Boost_RANDOM_LIBRARY} - ${Boost_REGEX_LIBRARY} - ${Boost_DATE_TIME_LIBRARY} - ${EXTRALINKS} - ${Boost_FRAMEWORK} - ${OPENSSL_LIBRARIES} - ${COREFOUNDATION} - ${ANDROID_STL_FLAGS} - ${ZLIB_LIBRARIES} +# Websockets component +if(CPPREST_WEBSOCKETS_IMPL STREQUAL "none") + target_compile_definitions(cpprest PUBLIC -DCPPREST_EXCLUDE_WEBSOCKETS=1) +elseif(CPPREST_WEBSOCKETS_IMPL STREQUAL "winrt") +elseif(CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") + set(CPPREST_USES_WEBSOCKETPP ON) + set(CPPREST_USES_BOOST ON) + set(CPPREST_USES_OPENSSL ON) + set(CPPREST_USES_ZLIB ON) +else() + message(FATAL_ERROR "Invalid implementation") +endif() + +# Compression component +if(CPPREST_EXCLUDE_COMPRESSION) + target_compile_definitions(cpprest PUBLIC -DCPPREST_EXCLUDE_COMPRESSION=1) +else() + set(CPPREST_USES_ZLIB ON) +endif() + +# PPLX component +if(CPPREST_PPLX_IMPL STREQUAL "apple") + find_library(COREFOUNDATION CoreFoundation "/") + find_library(SECURITY Security "/") + target_link_libraries(cpprest PRIVATE ${COREFOUNDATION} ${SECURITY}) +elseif(CPPREST_PPLX_IMPL STREQUAL "linux") +elseif(CPPREST_PPLX_IMPL STREQUAL "win") +else() + message(FATAL_ERROR "Invalid implementation") +endif() + +# Http client component +if(CPPREST_HTTP_CLIENT_IMPL STREQUAL "asio") + set(CPPREST_USES_BOOST ON) + set(CPPREST_USES_OPENSSL ON) + target_compile_definitions(cpprest PUBLIC -DCPPREST_FORCE_HTTP_CLIENT_ASIO) +elseif(CPPREST_HTTP_CLIENT_IMPL STREQUAL "winhttp") + target_link_libraries(cpprest PRIVATE + httpapi.lib + Winhttp.lib ) +elseif(CPPREST_HTTP_CLIENT_IMPL STREQUAL "winrt") +else() + message(FATAL_ERROR "Invalid implementation") +endif() + +# fileio streams component +if(CPPREST_FILEIO_IMPL STREQUAL "win32") +elseif(CPPREST_FILEIO_IMPL STREQUAL "winrt") +elseif(CPPREST_FILEIO_IMPL STREQUAL "posix") +else() + message(FATAL_ERROR "Invalid implementation") +endif() + +# http listener component +if(CPPREST_HTTP_LISTENER_IMPL STREQUAL "asio") + set(CPPREST_USES_BOOST ON) + set(CPPREST_USES_OPENSSL ON) + target_compile_definitions(cpprest PUBLIC -DCPPREST_FORCE_HTTP_LISTENER_ASIO) +elseif(CPPREST_HTTP_LISTENER_IMPL STREQUAL "httpsys") +elseif(CPPREST_HTTP_LISTENER_IMPL STREQUAL "none") +else() + message(FATAL_ERROR "Invalid implementation") +endif() + +# Add any libraries that were used. +if(CPPREST_USES_WEBSOCKETPP) + cpprest_find_websocketpp() + target_include_directories(cpprest SYSTEM PRIVATE ${WEBSOCKETPP_INCLUDE_DIR}) +endif() +if(CPPREST_USES_BOOST) + cpprest_find_boost() + target_link_libraries(cpprest PUBLIC ${Boost_LIBRARIES}) + target_include_directories(cpprest SYSTEM PUBLIC ${Boost_INCLUDE_DIR}) +endif() +if(CPPREST_USES_OPENSSL) + cpprest_find_openssl() + target_link_libraries(cpprest PUBLIC ${OPENSSL_LIBRARIES}) + target_include_directories(cpprest SYSTEM PUBLIC ${OPENSSL_INCLUDE_DIR}) + if (NOT _SSL_LEAK_SUPPRESS_AVAILABLE) + # libressl doesn't ship with the cleanup method being used in ws_client_wspp + target_compile_definitions(cpprest PRIVATE -DCPPREST_NO_SSL_LEAK_SUPPRESS) + endif() +endif() +if(CPPREST_USES_ZLIB) + cpprest_find_zlib() + target_link_libraries(cpprest PUBLIC ${ZLIB_LIBRARIES}) + target_include_directories(cpprest SYSTEM PUBLIC ${ZLIB_INCLUDE_DIR}) +endif() +if(ANDROID) + target_link_libraries(cpprest PRIVATE ${ANDROID_STL_FLAGS}) +endif() # Portions specific to cpprest binary versioning. set (CPPREST_VERSION_MAJOR 2) @@ -154,7 +259,16 @@ endif() install( TARGETS cpprest + EXPORT ${CPPREST_EXPORT_NAME} RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib - ) +) + +if(CPPREST_INSTALL_HEADERS) + install(FILES ${HEADERS_CPPREST} DESTINATION include/cpprest) + install(FILES ${HEADERS_PPLX} DESTINATION include/pplx) + install(FILES ${HEADERS_DETAILS} DESTINATION include/cpprest/details) +endif() + +install(EXPORT ${CPPREST_EXPORT_NAME} DESTINATION ${CPPREST_EXPORT_DIR}) diff --git a/Release/tests/common/TestRunner/CMakeLists.txt b/Release/tests/common/TestRunner/CMakeLists.txt index 29669d277a..d64b20cea7 100644 --- a/Release/tests/common/TestRunner/CMakeLists.txt +++ b/Release/tests/common/TestRunner/CMakeLists.txt @@ -1,7 +1,3 @@ -include_directories(${Casablanca_INCLUDE_DIRS} - ../UnitTestpp - ) - set(TR_SOURCES test_runner.cpp test_module_loader.cpp @@ -23,7 +19,6 @@ if(NOT IOS AND NOT ANDROID) ) target_link_libraries(test_runner - ${Boost_LIBRARIES} unittestpp ${CMAKE_DL_LIBS} ) diff --git a/Release/tests/common/UnitTestpp/CMakeLists.txt b/Release/tests/common/UnitTestpp/CMakeLists.txt index 2c8205aa13..43a2d4de43 100644 --- a/Release/tests/common/UnitTestpp/CMakeLists.txt +++ b/Release/tests/common/UnitTestpp/CMakeLists.txt @@ -1,5 +1,3 @@ -include_directories(${Casablanca_INCLUDE_DIR} src .) - set(UT_SOURCES src/AssertException.cpp src/CompositeTestReporter.cpp @@ -49,4 +47,12 @@ elseif(WIN32) endif() add_library(unittestpp ${UT_SOURCES}) -target_link_libraries(unittestpp ${ANDROID_STL_FLAGS}) \ No newline at end of file +if(UNIX) + cpprest_find_boost() + target_include_directories(unittestpp PUBLIC ${Boost_INCLUDE_DIR}) + target_link_libraries(unittestpp PUBLIC ${Boost_LIBRARIES}) +endif() +target_link_libraries(unittestpp ${ANDROID_STL_FLAGS}) + +target_include_directories(unittestpp PRIVATE src) +target_include_directories(unittestpp PUBLIC .) diff --git a/Release/tests/functional/http/client/CMakeLists.txt b/Release/tests/functional/http/client/CMakeLists.txt index d18060894f..ba86825db9 100644 --- a/Release/tests/functional/http/client/CMakeLists.txt +++ b/Release/tests/functional/http/client/CMakeLists.txt @@ -27,6 +27,11 @@ set(SOURCES status_code_reason_phrase_tests.cpp to_string_tests.cpp http_client_fuzz_tests.cpp + stdafx.cpp ) add_casablanca_test(httpclient_test SOURCES) + +if(WIN32) + target_link_libraries(httpclient_test winhttp) +endif() diff --git a/Release/tests/functional/http/utilities/CMakeLists.txt b/Release/tests/functional/http/utilities/CMakeLists.txt index a36e9614e3..279df76749 100644 --- a/Release/tests/functional/http/utilities/CMakeLists.txt +++ b/Release/tests/functional/http/utilities/CMakeLists.txt @@ -15,6 +15,6 @@ add_library(httptest_utilities ${SOURCES}) target_link_libraries(httptest_utilities unittestpp common_utilities + cpprest ${BOOST_LIBRARIES} - ${Casablanca_LIBRARIES} ) diff --git a/Release/tests/functional/json/CMakeLists.txt b/Release/tests/functional/json/CMakeLists.txt index f6d6ff7587..a1ece2f5d0 100644 --- a/Release/tests/functional/json/CMakeLists.txt +++ b/Release/tests/functional/json/CMakeLists.txt @@ -5,6 +5,7 @@ set (SOURCES to_as_and_operators_tests.cpp iterator_tests.cpp json_numbers_tests.cpp + stdafx.cpp ) if (NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) list(APPEND SOURCES fuzz_tests.cpp) diff --git a/Release/tests/functional/streams/CMakeLists.txt b/Release/tests/functional/streams/CMakeLists.txt index c7e1147966..bb532557c3 100644 --- a/Release/tests/functional/streams/CMakeLists.txt +++ b/Release/tests/functional/streams/CMakeLists.txt @@ -4,6 +4,7 @@ set(SOURCES memstream_tests.cpp ostream_tests.cpp stdstream_tests.cpp + stdafx.cpp ) if (NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) list(APPEND SOURCES fuzz_tests.cpp) @@ -14,3 +15,8 @@ else () list(APPEND SOURCES winrt_interop_tests.cpp) endif () add_casablanca_test(streams_test SOURCES) + +if(NOT CPPREST_WEBSOCKETS_IMPL STREQUAL "none") + cpprest_find_boost() + target_include_directories(streams_test PRIVATE ${Boost_INCLUDE_DIR}) +endif() \ No newline at end of file diff --git a/Release/tests/functional/uri/CMakeLists.txt b/Release/tests/functional/uri/CMakeLists.txt index 4a55dd12ea..19c2052817 100644 --- a/Release/tests/functional/uri/CMakeLists.txt +++ b/Release/tests/functional/uri/CMakeLists.txt @@ -8,6 +8,7 @@ set(SOURCES operator_tests.cpp splitting_tests.cpp uri_builder_tests.cpp + stdafx.cpp ) add_casablanca_test(${LIB}uri_test SOURCES) diff --git a/Release/tests/functional/utils/CMakeLists.txt b/Release/tests/functional/utils/CMakeLists.txt index 7d72935850..e2d0e6bca3 100644 --- a/Release/tests/functional/utils/CMakeLists.txt +++ b/Release/tests/functional/utils/CMakeLists.txt @@ -4,6 +4,11 @@ set(SOURCES strings.cpp macro_test.cpp nonce_generator_tests.cpp + stdafx.cpp ) add_casablanca_test(${LIB}utils_test SOURCES) + +if(CMAKE_COMPILER_IS_GNUCXX) + target_compile_options(${LIB}utils_test PRIVATE "-Wno-deprecated-declarations") +endif() \ No newline at end of file diff --git a/Release/tests/functional/websockets/CMakeLists.txt b/Release/tests/functional/websockets/CMakeLists.txt index cd373a50d5..eae5bfb377 100644 --- a/Release/tests/functional/websockets/CMakeLists.txt +++ b/Release/tests/functional/websockets/CMakeLists.txt @@ -8,14 +8,27 @@ if (NOT CPPREST_EXCLUDE_WEBSOCKETS) add_library(websockettest_utilities ${TEST_LIBRARY_TARGET_TYPE} ${SOURCES}) target_compile_definitions(websockettest_utilities PRIVATE -DWEBSOCKETTESTUTILITY_EXPORTS) + if(NOT WIN32) + target_compile_definitions(websockettest_utilities PRIVATE "-DWEBSOCKET_UTILITY_API=__attribute__ ((visibility (\"default\")))") + target_compile_definitions(websockettest_utilities INTERFACE "-DWEBSOCKET_UTILITY_API=") + endif() if (NOT TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT") - target_link_libraries(websockettest_utilities + target_link_libraries(websockettest_utilities PRIVATE unittestpp common_utilities - ${BOOST_LIBRARIES} - ${Casablanca_LIBRARIES} + cpprest ) endif() + if(CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") + cpprest_find_boost() + cpprest_find_zlib() + cpprest_find_openssl() + cpprest_find_websocketpp() + + target_include_directories(websockettest_utilities SYSTEM PRIVATE ${Boost_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ${WEBSOCKETPP_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}) + target_link_libraries(websockettest_utilities PRIVATE ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES}) + endif() + add_subdirectory(client) endif() diff --git a/Release/tests/functional/websockets/client/CMakeLists.txt b/Release/tests/functional/websockets/client/CMakeLists.txt index 9cb347ebb5..a2597dac62 100644 --- a/Release/tests/functional/websockets/client/CMakeLists.txt +++ b/Release/tests/functional/websockets/client/CMakeLists.txt @@ -8,6 +8,7 @@ if (NOT CPPREST_EXCLUDE_WEBSOCKETS) error_tests.cpp receive_msg_tests.cpp send_msg_tests.cpp + stdafx.cpp ) add_casablanca_test(websocketclient_test SOURCES) From dcfb119f7a77dc89e01f7b141a383f5750c00adb Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 09:29:34 -0800 Subject: [PATCH 007/438] Fix std::getenv warning in BingRequest on Windows --- Release/samples/BingRequest/bingrequest.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Release/samples/BingRequest/bingrequest.cpp b/Release/samples/BingRequest/bingrequest.cpp index f6b1ae980d..faa0938652 100644 --- a/Release/samples/BingRequest/bingrequest.cpp +++ b/Release/samples/BingRequest/bingrequest.cpp @@ -25,9 +25,17 @@ using namespace concurrency::streams; web::http::client::http_client_config client_config_for_proxy() { web::http::client::http_client_config client_config; - +#ifdef _WIN32 + wchar_t* pValue; + size_t len; + auto err = _wdupenv_s(&pValue, &len, L"http_proxy"); + if (!err) { + std::unique_ptr holder(pValue, [](wchar_t* p) { free(p); }); + uri proxy_uri(std::wstring(pValue, len)); +#else if(const char* env_http_proxy = std::getenv("http_proxy")) { uri proxy_uri(utility::conversions::to_string_t(env_http_proxy)); +#endif web::web_proxy proxy(proxy_uri); client_config.set_proxy(proxy); } From 7d2a9a2073b1e21564f4ff019d97120a457abe79 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 09:29:34 -0800 Subject: [PATCH 008/438] utility::conversion::to_XYZ() should transparently forward references when possible --- Release/include/cpprest/asyncrt_utils.h | 40 +++++++++++++++++++++++-- Release/src/utilities/asyncrt_utils.cpp | 28 +++++------------ 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index 1c3bba979a..2f2ad2df32 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -100,28 +100,43 @@ namespace conversions /// /// A single byte character UTF-8 string. /// A platform dependent string type. +#ifdef _UTF16_STRINGS _ASYNCRTIMP utility::string_t __cdecl to_string_t(std::string &&s); +#else + inline utility::string_t&& to_string_t(std::string &&s) { return std::move(s); } +#endif /// /// Converts to a platform dependent Unicode string type. /// /// A two byte character UTF-16 string. /// A platform dependent string type. +#ifdef _UTF16_STRINGS + inline utility::string_t&& to_string_t(utf16string &&s) { return std::move(s); } +#else _ASYNCRTIMP utility::string_t __cdecl to_string_t(utf16string &&s); - +#endif /// /// Converts to a platform dependent Unicode string type. /// /// A single byte character UTF-8 string. /// A platform dependent string type. +#ifdef _UTF16_STRINGS _ASYNCRTIMP utility::string_t __cdecl to_string_t(const std::string &s); +#else + inline const utility::string_t& to_string_t(const std::string &s) { return s; } +#endif /// /// Converts to a platform dependent Unicode string type. /// /// A two byte character UTF-16 string. /// A platform dependent string type. +#ifdef _UTF16_STRINGS + inline const utility::string_t& to_string_t(const utf16string &s) { return s; } +#else _ASYNCRTIMP utility::string_t __cdecl to_string_t(const utf16string &s); +#endif /// /// Converts to a UTF-16 from string. @@ -135,14 +150,33 @@ namespace conversions /// /// A two byte character UTF-16 string. /// A two byte character UTF-16 string. - _ASYNCRTIMP utf16string __cdecl to_utf16string(utf16string value); + inline const utf16string& to_utf16string(const utf16string& value) + { + return value; + } + /// + /// Converts to a UTF-16 from string. + /// + /// A two byte character UTF-16 string. + /// A two byte character UTF-16 string. + inline utf16string&& to_utf16string(utf16string&& value) + { + return std::move(value); + } + + /// + /// Converts to a UTF-8 string. + /// + /// A single byte character UTF-8 string. + /// A single byte character UTF-8 string. + inline std::string&& to_utf8string(std::string&& value) { return std::move(value); } /// /// Converts to a UTF-8 string. /// /// A single byte character UTF-8 string. /// A single byte character UTF-8 string. - _ASYNCRTIMP std::string __cdecl to_utf8string(std::string value); + inline const std::string& to_utf8string(const std::string& value) { return value; } /// /// Converts to a UTF-8 string. diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index 52aa7354cd..d5921d07f2 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -438,50 +438,38 @@ utf8string __cdecl conversions::latin1_to_utf8(const std::string &s) return utf16_to_utf8(latin1_to_utf16(s)); } +#ifndef _UTF16_STRINGS utility::string_t __cdecl conversions::to_string_t(utf16string &&s) { -#ifdef _UTF16_STRINGS - return std::move(s); -#else return utf16_to_utf8(std::move(s)); -#endif } +#endif +#ifdef _UTF16_STRINGS utility::string_t __cdecl conversions::to_string_t(std::string &&s) { -#ifdef _UTF16_STRINGS return utf8_to_utf16(std::move(s)); -#else - return std::move(s); -#endif } +#endif +#ifndef _UTF16_STRINGS utility::string_t __cdecl conversions::to_string_t(const utf16string &s) { -#ifdef _UTF16_STRINGS - return s; -#else return utf16_to_utf8(s); -#endif } +#endif +#ifdef _UTF16_STRINGS utility::string_t __cdecl conversions::to_string_t(const std::string &s) { -#ifdef _UTF16_STRINGS return utf8_to_utf16(s); -#else - return s; -#endif } - -std::string __cdecl conversions::to_utf8string(std::string value) { return value; } +#endif std::string __cdecl conversions::to_utf8string(const utf16string &value) { return utf16_to_utf8(value); } utf16string __cdecl conversions::to_utf16string(const std::string &value) { return utf8_to_utf16(value); } -utf16string __cdecl conversions::to_utf16string(utf16string value) { return value; } - #ifndef WIN32 datetime datetime::timeval_to_datetime(const timeval &time) { From 29becf8f77079f39a06fe394610ef5f22e49a019 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 09:29:34 -0800 Subject: [PATCH 009/438] Deprecate and remove all uses of utility::conversions::print_string/scan_string. We should eliminate all locale-dependent code internal to the library to enable more consistent behavior on all machines. --- Release/include/cpprest/asyncrt_utils.h | 84 ++++++++++++++++--- Release/include/cpprest/http_headers.h | 4 +- Release/include/cpprest/oauth1.h | 2 +- Release/include/cpprest/uri_builder.h | 2 +- Release/src/http/client/http_client_asio.cpp | 10 ++- Release/src/http/common/http_msg.cpp | 2 +- .../src/http/listener/http_server_asio.cpp | 5 ++ Release/src/uri/uri.cpp | 2 +- Release/src/uri/uri_parser.cpp | 2 +- .../functional/http/client/header_tests.cpp | 2 +- 10 files changed, 92 insertions(+), 23 deletions(-) diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index 2f2ad2df32..521e338964 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -201,7 +201,8 @@ namespace conversions _ASYNCRTIMP std::vector __cdecl from_base64(const utility::string_t& str); template - utility::string_t print_string(const Source &val, const std::locale &loc) + CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if locale support is required.") + utility::string_t print_string(const Source &val, const std::locale& loc = std::locale()) { utility::ostringstream_t oss; oss.imbue(loc); @@ -213,19 +214,81 @@ namespace conversions return oss.str(); } - template - utility::string_t print_string(const Source &val) + CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if locale support is required.") + inline utility::string_t print_string(const utility::string_t &val) { - return print_string(val, std::locale()); + return val; } - inline utility::string_t print_string(const utility::string_t &val) + namespace details { - return val; + +#if defined(__ANDROID__) + template + inline std::string to_string(const T& t) + { + std::ostringstream os; + os.imbue(std::locale::classic()); + os << t; + return os.str(); + } +#endif + + template + inline utility::string_t to_string_t(T&& t) + { +#ifdef _UTF16_STRINGS + using std::to_wstring; + return to_wstring(std::forward(t)); +#else +#if !defined(__ANDROID__) + using std::to_string; +#endif + return to_string(std::forward(t)); +#endif + } + + template + utility::string_t print_string(const Source &val) + { + utility::ostringstream_t oss; + oss.imbue(std::locale::classic()); + oss << val; + if (oss.bad()) + { + throw std::bad_cast(); + } + return oss.str(); + } + + inline const utility::string_t& print_string(const utility::string_t &val) + { + return val; + } + + template + Target scan_string(const utility::string_t &str) + { + Target t; + utility::istringstream_t iss(str); + iss.imbue(std::locale::classic()); + iss >> t; + if (iss.bad()) + { + throw std::bad_cast(); + } + return t; + } + + inline const utility::string_t& scan_string(const utility::string_t &str) + { + return str; + } } template - Target scan_string(const utility::string_t &str, const std::locale &loc) + CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if locale support is required.") + Target scan_string(const utility::string_t &str, const std::locale &loc = std::locale()) { Target t; utility::istringstream_t iss(str); @@ -238,12 +301,7 @@ namespace conversions return t; } - template - Target scan_string(const utility::string_t &str) - { - return scan_string(str, std::locale()); - } - + CASABLANCA_DEPRECATED("All locale-sensitive APIs will be removed in a future update. Use stringstreams directly if locale support is required.") inline utility::string_t scan_string(const utility::string_t &str) { return str; diff --git a/Release/include/cpprest/http_headers.h b/Release/include/cpprest/http_headers.h index c352b49bb7..dc2c420dc8 100644 --- a/Release/include/cpprest/http_headers.h +++ b/Release/include/cpprest/http_headers.h @@ -147,11 +147,11 @@ class http_headers { if (has(name)) { - m_headers[name].append(_XPLATSTR(", ")).append(utility::conversions::print_string(value)); + m_headers[name].append(_XPLATSTR(", ")).append(utility::conversions::details::print_string(value)); } else { - m_headers[name] = utility::conversions::print_string(value); + m_headers[name] = utility::conversions::details::print_string(value); } } diff --git a/Release/include/cpprest/oauth1.h b/Release/include/cpprest/oauth1.h index 1dc790b2e2..24a10c7d79 100755 --- a/Release/include/cpprest/oauth1.h +++ b/Release/include/cpprest/oauth1.h @@ -501,7 +501,7 @@ class oauth1_config static utility::string_t _generate_timestamp() { - return utility::conversions::print_string(utility::datetime::utc_timestamp(), std::locale::classic()); + return utility::conversions::details::to_string_t(utility::datetime::utc_timestamp()); } _ASYNCRTIMP static std::vector __cdecl _hmac_sha1(const utility::string_t& key, const utility::string_t& data); diff --git a/Release/include/cpprest/uri_builder.h b/Release/include/cpprest/uri_builder.h index 564a22a592..8464d1e0af 100644 --- a/Release/include/cpprest/uri_builder.h +++ b/Release/include/cpprest/uri_builder.h @@ -226,7 +226,7 @@ namespace web uri_builder &append_query(const utility::string_t &name, const T &value, bool do_encoding = true) { auto encodedName = name; - auto encodedValue = ::utility::conversions::print_string(value, std::locale::classic()); + auto encodedValue = utility::conversions::details::print_string(value); if (do_encoding) { diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index d9214d18e8..1fbbc6bbe4 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -41,6 +41,12 @@ using boost::asio::ip::tcp; +#ifdef __ANDROID__ +using utility::conversions::details::to_string; +#else +using std::to_string; +#endif + #define CRLF std::string("\r\n") namespace web { namespace http @@ -439,7 +445,7 @@ class asio_context : public request_context, public std::enable_shared_from_this m_context->m_timer.start(); - tcp::resolver::query query(proxy_host, utility::conversions::print_string(proxy_port, std::locale::classic())); + tcp::resolver::query query(utility::conversions::to_utf8string(proxy_host), to_string(proxy_port)); auto client = std::static_pointer_cast(m_context->m_http_client); client->m_resolver.async_resolve(query, boost::bind(&ssl_proxy_tunnel::handle_resolve, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::iterator)); @@ -724,7 +730,7 @@ class asio_context : public request_context, public std::enable_shared_from_this auto tcp_host = proxy_type == http_proxy_type::http ? proxy_host : host; auto tcp_port = proxy_type == http_proxy_type::http ? proxy_port : port; - tcp::resolver::query query(tcp_host, utility::conversions::print_string(tcp_port, std::locale::classic())); + tcp::resolver::query query(tcp_host, to_string(tcp_port)); auto client = std::static_pointer_cast(ctx->m_http_client); client->m_resolver.async_resolve(query, boost::bind(&asio_context::handle_resolve, ctx, boost::asio::placeholders::error, boost::asio::placeholders::iterator)); } diff --git a/Release/src/http/common/http_msg.cpp b/Release/src/http/common/http_msg.cpp index 7c51412b20..fd450c4ae4 100644 --- a/Release/src/http/common/http_msg.cpp +++ b/Release/src/http/common/http_msg.cpp @@ -208,7 +208,7 @@ utility::size64_t http_headers::content_length() const void http_headers::set_content_length(utility::size64_t length) { - m_headers[http::header_names::content_length] = utility::conversions::print_string(length, std::locale::classic()); + m_headers[http::header_names::content_length] = utility::conversions::details::to_string_t(length); } namespace details { diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 46a3213d2e..5619c2676b 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -22,6 +22,11 @@ #pragma clang diagnostic pop #endif +#ifdef __ANDROID__ +using utility::conversions::details::to_string; +#else +using std::to_string; +#endif using namespace boost::asio; using namespace boost::asio::ip; diff --git a/Release/src/uri/uri.cpp b/Release/src/uri/uri.cpp index 0f33aa37fb..fb395edf5d 100644 --- a/Release/src/uri/uri.cpp +++ b/Release/src/uri/uri.cpp @@ -61,7 +61,7 @@ utility::string_t uri_components::join() if (m_port > 0) { - ret.append({ _XPLATSTR(':') }).append(utility::conversions::print_string(m_port, std::locale::classic())); + ret.append({ _XPLATSTR(':') }).append(utility::conversions::details::to_string_t(m_port)); } } diff --git a/Release/src/uri/uri_parser.cpp b/Release/src/uri/uri_parser.cpp index 8198559b40..2778ae64a2 100644 --- a/Release/src/uri/uri_parser.cpp +++ b/Release/src/uri/uri_parser.cpp @@ -266,7 +266,7 @@ bool inner_parse( //skip the colon port_begin++; - *port = utility::conversions::scan_string(utility::string_t(port_begin, authority_end), std::locale::classic()); + *port = utility::conversions::details::scan_string(utility::string_t(port_begin, authority_end)); } else { diff --git a/Release/tests/functional/http/client/header_tests.cpp b/Release/tests/functional/http/client/header_tests.cpp index 7a59d6f260..1b92d3a772 100644 --- a/Release/tests/functional/http/client/header_tests.cpp +++ b/Release/tests/functional/http/client/header_tests.cpp @@ -379,7 +379,7 @@ TEST_FIXTURE(uri_address, overwrite_http_header) // Test default case of cpprestsdk setting host header as host:port auto& host = m_uri.host(); int port = m_uri.port(); - utility::string_t expected_default_header = host + U(":") + utility::conversions::print_string(port); + utility::string_t expected_default_header = host + U(":") + utility::conversions::details::to_string_t(port); http_request default_host_headers_request(methods::GET); scoped.server()->next_request().then([&](test_request *p_request) { From 3e4e3e9a85ccc65b16fb1cf1ecc89ea79e8e5925 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 09:29:34 -0800 Subject: [PATCH 010/438] Move definitions of flatten_http_headers and parse_headers_string to http_client_impl.h. --- Release/include/cpprest/http_headers.h | 14 -------------- Release/src/http/client/http_client_impl.h | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Release/include/cpprest/http_headers.h b/Release/include/cpprest/http_headers.h index dc2c420dc8..4c7af7cf27 100644 --- a/Release/include/cpprest/http_headers.h +++ b/Release/include/cpprest/http_headers.h @@ -316,18 +316,4 @@ class http_headers std::map m_headers; }; -namespace details { - - /// - /// Serialize the http_headers into name:value pairs separated by a carriage return and line feed. - /// - utility::string_t flatten_http_headers(const http_headers &headers); -#if defined(_WIN32) - /// - /// Parses a string containing Http headers. - /// - void parse_headers_string(_Inout_z_ utf16char *headersStr, http_headers &headers); -#endif -} - }} \ No newline at end of file diff --git a/Release/src/http/client/http_client_impl.h b/Release/src/http/client/http_client_impl.h index d374cce619..e203955591 100644 --- a/Release/src/http/client/http_client_impl.h +++ b/Release/src/http/client/http_client_impl.h @@ -20,6 +20,21 @@ #include #include +namespace web { namespace http { namespace details { + +/// +/// Serialize the http_headers into name:value pairs separated by a carriage return and line feed. +/// +utility::string_t flatten_http_headers(const http_headers &headers); +#if defined(_WIN32) +/// +/// Parses a string containing Http headers. +/// +void parse_headers_string(_Inout_z_ utf16char *headersStr, http_headers &headers); +#endif + +}}} + namespace web { namespace http { namespace client { namespace details { class _http_client_communicator; From b11cf34fc4626622235f0744035c947344454650 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 09:29:34 -0800 Subject: [PATCH 011/438] Rename web::credentials::decrypt to web::credentials::_internal_decrypt and make public. Note: this function is still intended only for internal use. --- .../include/cpprest/details/web_utilities.h | 10 +-- Release/src/http/client/http_client_asio.cpp | 69 +++++++------------ .../src/http/client/http_client_winhttp.cpp | 2 +- Release/src/http/client/http_client_winrt.cpp | 4 +- .../src/websockets/client/ws_client_winrt.cpp | 4 +- .../src/websockets/client/ws_client_wspp.cpp | 2 +- 6 files changed, 32 insertions(+), 59 deletions(-) diff --git a/Release/include/cpprest/details/web_utilities.h b/Release/include/cpprest/details/web_utilities.h index b7bf2276bd..ba6416546e 100644 --- a/Release/include/cpprest/details/web_utilities.h +++ b/Release/include/cpprest/details/web_utilities.h @@ -110,14 +110,7 @@ class credentials /// true if user name and password is set, false otherwise. bool is_set() const { return !m_username.empty(); } -private: - friend class http::client::details::winhttp_client; - friend class http::client::details::winrt_client; - friend class http::client::details::asio_context; - friend class websockets::client::details::winrt_callback_client; - friend class websockets::client::details::wspp_callback_client; - - details::plaintext_string decrypt() const + details::plaintext_string _internal_decrypt() const { // Encryption APIs not supported on XP #if defined(_WIN32) && !defined(CPPREST_TARGET_XP) @@ -127,6 +120,7 @@ class credentials #endif } +private: ::utility::string_t m_username; #if defined(_WIN32) && !defined(CPPREST_TARGET_XP) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 1fbbc6bbe4..39b397c5ed 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -68,6 +68,14 @@ enum class httpclient_errorcode_context close }; +static std::string generate_base64_userpass(const ::web::credentials& creds) +{ + auto userpass = creds.username() + U(":") + *creds._internal_decrypt(); + auto&& u8_userpass = utility::conversions::to_utf8string(userpass); + std::vector credentials_buffer(u8_userpass.begin(), u8_userpass.end()); + return utility::conversions::to_utf8string(utility::conversions::to_base64(credentials_buffer)); +} + class asio_connection_pool; class asio_connection @@ -529,9 +537,7 @@ class asio_context : public request_context, public std::enable_shared_from_this if (status_code != 200) { - utility::stringstream_t err_ss; - err_ss << U("Expected a 200 response from proxy, received: ") << status_code; - m_context->report_error(err_ss.str(), ec, httpclient_errorcode_context::readheader); + m_context->report_error("Expected a 200 response from proxy, received: " + to_string(status_code), ec, httpclient_errorcode_context::readheader); return; } @@ -656,7 +662,7 @@ class asio_context : public request_context, public std::enable_shared_from_this } // Extra request headers are constructed here. - utility::string_t extra_headers; + std::string extra_headers; // Add header for basic proxy authentication if (proxy_type == http_proxy_type::http && ctx->m_http_client->client_config().proxy().credentials().is_set()) @@ -672,12 +678,7 @@ class asio_context : public request_context, public std::enable_shared_from_this // Add the header needed to request a compressed response if supported on this platform and it has been specified in the config if (web::http::details::compression::stream_decompressor::is_supported() && ctx->m_http_client->client_config().request_compressed_response()) { - utility::string_t accept_encoding_header; - accept_encoding_header.append(header_names::accept_encoding); - accept_encoding_header.append(": deflate, gzip"); - accept_encoding_header.append(CRLF); - - extra_headers.append(accept_encoding_header); + extra_headers.append("Accept-Encoding: deflate, gzip\r\n"); } // Check user specified transfer-encoding. @@ -692,17 +693,15 @@ class asio_context : public request_context, public std::enable_shared_from_this if (ctx->m_request.body()) { ctx->m_needChunked = true; - extra_headers.append(header_names::transfer_encoding); - extra_headers.append(":chunked" + CRLF); + extra_headers.append("Transfer-Encoding:chunked\r\n"); } } if (proxy_type == http_proxy_type::http) { - extra_headers.append(header_names::cache_control); - extra_headers.append(": no-store, no-cache" + CRLF); - extra_headers.append(header_names::pragma); - extra_headers.append(": no-cache" + CRLF); + extra_headers.append( + "Cache-Control: no-store, no-cache\r\n" + "Pragma: no-cache\r\n"); } request_stream << ::web::http::details::flatten_http_headers(ctx->m_request.headers()); @@ -778,38 +777,20 @@ class asio_context : public request_context, public std::enable_shared_from_this } private: - utility::string_t generate_basic_auth_header() + std::string generate_basic_auth_header() { - utility::string_t header; - - header.append(header_names::authorization); - header.append(": Basic "); - - auto credential_str = web::details::plaintext_string(new ::utility::string_t(m_http_client->client_config().credentials().username())); - credential_str->append(":"); - credential_str->append(*m_http_client->client_config().credentials().decrypt()); - - std::vector credentials_buffer(credential_str->begin(), credential_str->end()); - - header.append(utility::conversions::to_base64(credentials_buffer)); + std::string header; + header.append("Authorization: Basic "); + header.append(generate_base64_userpass(m_http_client->client_config().credentials())); header.append(CRLF); return header; } - utility::string_t generate_basic_proxy_auth_header() + std::string generate_basic_proxy_auth_header() { - utility::string_t header; - - header.append(header_names::proxy_authorization); - header.append(": Basic "); - - auto credential_str = web::details::plaintext_string(new ::utility::string_t(m_http_client->client_config().proxy().credentials().username())); - credential_str->append(":"); - credential_str->append(*m_http_client->client_config().proxy().credentials().decrypt()); - - std::vector credentials_buffer(credential_str->begin(), credential_str->end()); - - header.append(utility::conversions::to_base64(credentials_buffer)); + std::string header; + header.append("Proxy-Authorization: Basic "); + header.append(generate_base64_userpass(m_http_client->client_config().credentials())); header.append(CRLF); return header; } @@ -1232,9 +1213,7 @@ class asio_context : public request_context, public std::enable_shared_from_this } else { - utility::string_t error = U("Unsupported compression algorithm in the Content Encoding header: "); - error += content_encoding; - report_exception(std::runtime_error(error)); + report_exception(std::runtime_error("Unsupported compression algorithm in the Content Encoding header: " + utility::conversions::to_utf8string(content_encoding))); } } diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index a5ba533689..d163962e8d 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -963,7 +963,7 @@ class winhttp_client : public _http_client_communicator // New scope to ensure plaintext password is cleared as soon as possible. { - auto password = cred.decrypt(); + auto password = cred._internal_decrypt(); if (!WinHttpSetCredentials( hRequestHandle, dwAuthTarget, diff --git a/Release/src/http/client/http_client_winrt.cpp b/Release/src/http/client/http_client_winrt.cpp index a1fd376325..e49144800f 100644 --- a/Release/src/http/client/http_client_winrt.cpp +++ b/Release/src/http/client/http_client_winrt.cpp @@ -442,13 +442,13 @@ class winrt_client : public _http_client_communicator if (client_cred.is_set()) { username = client_cred.username(); - password_plaintext = client_cred.decrypt(); + password_plaintext = client_cred._internal_decrypt(); password = password_plaintext->c_str(); } if (proxy_cred.is_set()) { proxy_username = proxy_cred.username(); - proxy_password_plaintext = proxy_cred.decrypt(); + proxy_password_plaintext = proxy_cred._internal_decrypt(); proxy_password = proxy_password_plaintext->c_str(); } diff --git a/Release/src/websockets/client/ws_client_winrt.cpp b/Release/src/websockets/client/ws_client_winrt.cpp index 107e7f57e4..2a18523926 100644 --- a/Release/src/websockets/client/ws_client_winrt.cpp +++ b/Release/src/websockets/client/ws_client_winrt.cpp @@ -102,7 +102,7 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: if (m_config.credentials().is_set()) { - auto password = m_config.credentials().decrypt(); + auto password = m_config.credentials()._internal_decrypt(); m_msg_websocket->Control->ServerCredential = ref new Windows::Security::Credentials::PasswordCredential("WebSocketClientCredentialResource", Platform::StringReference(m_config.credentials().username().c_str()), Platform::StringReference(password->c_str())); @@ -155,7 +155,7 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: const auto &proxy_cred = proxy.credentials(); if(proxy_cred.is_set()) { - auto password = proxy_cred.decrypt(); + auto password = proxy_cred._internal_decrypt(); m_msg_websocket->Control->ProxyCredential = ref new Windows::Security::Credentials::PasswordCredential("WebSocketClientProxyCredentialResource", Platform::StringReference(proxy_cred.username().c_str()), Platform::StringReference(password->c_str())); diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index a2f997531c..7ecc3687fd 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -351,7 +351,7 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: { con->set_proxy_basic_auth( utility::conversions::to_utf8string(cred.username()), - utility::conversions::to_utf8string(*cred.decrypt()), + utility::conversions::to_utf8string(*cred._internal_decrypt()), ec); if (ec) { From 6d6e053bd2520531d95a5e2148a1d5559dc5f989 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 09:29:34 -0800 Subject: [PATCH 012/438] Fix 3e4e3e9a for WinRT. --- Release/src/http/client/http_client_winrt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_winrt.cpp b/Release/src/http/client/http_client_winrt.cpp index e49144800f..d283b6ce93 100644 --- a/Release/src/http/client/http_client_winrt.cpp +++ b/Release/src/http/client/http_client_winrt.cpp @@ -92,7 +92,7 @@ class HttpRequestCallback : (*progress)(message_direction::upload, 0); } - parse_headers_string(hdrStr, response.headers()); + web::http::details::parse_headers_string(hdrStr, response.headers()); m_request->complete_headers(); } catch (...) From 154ce78e6841723b574abb50011206fa3a6d2d61 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 09:29:34 -0800 Subject: [PATCH 013/438] Avoid using recursive locks, they indicate poor understanding of code flow. --- Release/include/cpprest/details/http_server_asio.h | 2 +- Release/src/http/listener/http_server_asio.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Release/include/cpprest/details/http_server_asio.h b/Release/include/cpprest/details/http_server_asio.h index 16ca9fd08a..b7b1edc162 100644 --- a/Release/include/cpprest/details/http_server_asio.h +++ b/Release/include/cpprest/details/http_server_asio.h @@ -132,7 +132,7 @@ class hostport_listener std::map m_listeners; pplx::extensibility::reader_writer_lock_t m_listeners_lock; - pplx::extensibility::recursive_lock_t m_connections_lock; + std::mutex m_connections_lock; pplx::extensibility::event_t m_all_connections_complete; std::set m_connections; diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 5619c2676b..a86c73f749 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -221,8 +221,8 @@ void hostport_listener::on_accept(ip::tcp::socket* socket, const boost::system:: } else { + std::lock_guard lock(m_connections_lock); { - pplx::scoped_lock lock(m_connections_lock); m_connections.insert(new connection(std::unique_ptr(std::move(socket)), m_p_server, this, m_is_https, m_ssl_context_callback)); m_all_connections_complete.reset(); @@ -785,7 +785,7 @@ void connection::finish_request_response() { // kill the connection { - pplx::scoped_lock lock(m_p_parent->m_connections_lock); + std::lock_guard lock(m_p_parent->m_connections_lock); m_p_parent->m_connections.erase(this); if (m_p_parent->m_connections.empty()) { @@ -801,7 +801,7 @@ void hostport_listener::stop() { // halt existing connections { - pplx::scoped_lock lock(m_connections_lock); + std::lock_guard lock(m_connections_lock); m_acceptor.reset(); for(auto connection : m_connections) { From aa1242411778dcafc95c8c7cc515387ec8a25bcf Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 09:29:34 -0800 Subject: [PATCH 014/438] Move the choice of pthreads vs std::thread behind the DLL barrier. --- Release/include/pplx/threadpool.h | 97 +++---------------- Release/src/pplx/pplxlinux.cpp | 2 +- Release/src/pplx/threadpool.cpp | 96 +++++++++++++++++- .../pplx/pplx_test/pplx_op_test.cpp | 7 +- 4 files changed, 108 insertions(+), 94 deletions(-) diff --git a/Release/include/pplx/threadpool.h b/Release/include/pplx/threadpool.h index 1b25eb3871..c67db358a0 100644 --- a/Release/include/pplx/threadpool.h +++ b/Release/include/pplx/threadpool.h @@ -11,9 +11,6 @@ ***/ #pragma once -#include -#include - #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" @@ -25,15 +22,17 @@ #pragma clang diagnostic pop #endif -#if (defined(ANDROID) || defined(__ANDROID__)) +#if defined(__ANDROID__) #include #include #include "pplx/pplx.h" #endif +#include "cpprest/details/cpprest_compat.h" + namespace crossplat { -#if (defined(ANDROID) || defined(__ANDROID__)) +#if defined(__ANDROID__) // IDEA: Break this section into a separate android/jni header extern std::atomic JVM; JNIEnv* get_jvm_env(); @@ -53,98 +52,24 @@ using java_local_ref = std::unique_ptr::type, ja class threadpool { public: - - threadpool(size_t n) - : m_service(n), - m_work(m_service) - { - for (size_t i = 0; i < n; i++) - add_thread(); - } - static threadpool& shared_instance(); + _ASYNCRTIMP static std::unique_ptr __cdecl construct(size_t num_threads); - ~threadpool() - { - m_service.stop(); - for (auto iter = m_threads.begin(); iter != m_threads.end(); ++iter) - { - pthread_t t = *iter; - void* res; - pthread_join(t, &res); - } - } + virtual ~threadpool() = default; template + CASABLANCA_DEPRECATED("Use `.service().post(task)` directly.") void schedule(T task) { - m_service.post(task); - } - - boost::asio::io_service& service() - { - return m_service; - } - -private: - struct _cancel_thread { }; - - void add_thread() - { - pthread_t t; - auto result = pthread_create(&t, nullptr, &thread_start, this); - if (result == 0) - m_threads.push_back(t); + service().post(task); } - void remove_thread() - { - schedule([]() -> void { throw _cancel_thread(); }); - } + boost::asio::io_service& service() { return m_service; } -#if (defined(ANDROID) || defined(__ANDROID__)) - static void detach_from_java(void*) - { - JVM.load()->DetachCurrentThread(); - } -#endif - - static void* thread_start(void *arg) - { -#if (defined(ANDROID) || defined(__ANDROID__)) - // Calling get_jvm_env() here forces the thread to be attached. - get_jvm_env(); - pthread_cleanup_push(detach_from_java, nullptr); -#endif - threadpool* _this = reinterpret_cast(arg); - try - { - _this->m_service.run(); - } - catch (const _cancel_thread&) - { - // thread was cancelled - } - catch (...) - { - // Something bad happened -#if (defined(ANDROID) || defined(__ANDROID__)) - // Reach into the depths of the 'droid! - // NOTE: Uses internals of the bionic library - // Written against android ndk r9d, 7/26/2014 - __pthread_cleanup_pop(&__cleanup, true); - throw; -#endif - } -#if (defined(ANDROID) || defined(__ANDROID__)) - pthread_cleanup_pop(true); -#endif - return arg; - } +protected: + threadpool(size_t num_threads) : m_service(num_threads) {} - std::vector m_threads; boost::asio::io_service m_service; - boost::asio::io_service::work m_work; }; } diff --git a/Release/src/pplx/pplxlinux.cpp b/Release/src/pplx/pplxlinux.cpp index c618025206..b2dc524c86 100644 --- a/Release/src/pplx/pplxlinux.cpp +++ b/Release/src/pplx/pplxlinux.cpp @@ -40,7 +40,7 @@ namespace details { _PPLXIMP void linux_scheduler::schedule(TaskProc_t proc, void* param) { - crossplat::threadpool::shared_instance().schedule(boost::bind(proc, param)); + crossplat::threadpool::shared_instance().service().post(boost::bind(proc, param)); } } // namespace details diff --git a/Release/src/pplx/threadpool.cpp b/Release/src/pplx/threadpool.cpp index 1c2305207d..cdffabec57 100644 --- a/Release/src/pplx/threadpool.cpp +++ b/Release/src/pplx/threadpool.cpp @@ -6,14 +6,100 @@ **/ #include "stdafx.h" +#include "pplx/threadpool.h" + +#if !defined(_WIN32) +#define CPPREST_PTHREADS +#endif + +#if defined(CPPREST_PTHREADS) +#include +#else +#include +#endif + +#include + #if defined(__ANDROID__) #include #include #endif +namespace +{ + +struct threadpool_impl final : crossplat::threadpool +{ + threadpool_impl(size_t n) + : crossplat::threadpool(n) + , m_work(m_service) + { + for (size_t i = 0; i < n; i++) + add_thread(); + } + + ~threadpool_impl() + { + m_service.stop(); + for (auto iter = m_threads.begin(); iter != m_threads.end(); ++iter) + { +#if defined(CPPREST_PTHREADS) + pthread_t t = *iter; + void* res; + pthread_join(t, &res); +#else + iter->join(); +#endif + } + } + +private: + void add_thread() + { +#ifdef CPPREST_PTHREADS + pthread_t t; + auto result = pthread_create(&t, nullptr, &thread_start, this); + if (result == 0) + m_threads.push_back(t); +#else + m_threads.push_back(std::thread(&thread_start, this)); +#endif + } + +#if defined(__ANDROID__) + static void detach_from_java(void*) + { + crossplat::JVM.load()->DetachCurrentThread(); + } +#endif + + static void* thread_start(void *arg) CPPREST_NOEXCEPT + { +#if defined(__ANDROID__) + // Calling get_jvm_env() here forces the thread to be attached. + crossplat::get_jvm_env(); + pthread_cleanup_push(detach_from_java, nullptr); +#endif + threadpool_impl* _this = reinterpret_cast(arg); + _this->m_service.run(); +#if defined(__ANDROID__) + pthread_cleanup_pop(true); +#endif + return arg; + } + +#if defined(CPPREST_PTHREADS) + std::vector m_threads; +#else + std::vector m_threads; +#endif + boost::asio::io_service::work m_work; +}; +} + namespace crossplat { -#if (defined(ANDROID) || defined(__ANDROID__)) +#if defined(__ANDROID__) // This pointer will be 0-initialized by default (at load time). std::atomic JVM; @@ -42,7 +128,7 @@ JNIEnv* get_jvm_env() threadpool& threadpool::shared_instance() { abort_if_no_jvm(); - static threadpool s_shared(40); + static threadpool_impl s_shared(40); return s_shared; } @@ -51,7 +137,7 @@ threadpool& threadpool::shared_instance() // initialize the static shared threadpool threadpool& threadpool::shared_instance() { - static threadpool s_shared(40); + static threadpool_impl s_shared(40); return s_shared; } @@ -65,3 +151,7 @@ void cpprest_init(JavaVM* vm) { } #endif +std::unique_ptr crossplat::threadpool::construct(size_t num_threads) +{ + return std::unique_ptr(new threadpool_impl(num_threads)); +} diff --git a/Release/tests/functional/pplx/pplx_test/pplx_op_test.cpp b/Release/tests/functional/pplx/pplx_test/pplx_op_test.cpp index 4daeaad72d..8dea473918 100644 --- a/Release/tests/functional/pplx/pplx_test/pplx_op_test.cpp +++ b/Release/tests/functional/pplx/pplx_test/pplx_op_test.cpp @@ -56,18 +56,17 @@ class pplx_dflt_scheduler : public pplx::scheduler_interface class pplx_dflt_scheduler : public pplx::scheduler_interface { - crossplat::threadpool m_pool; + std::unique_ptr m_pool; virtual void schedule(pplx::TaskProc_t proc, void* param) { pplx::details::atomic_increment(s_flag); - m_pool.schedule([=]() -> void { proc(param); }); - + m_pool->service().post([=]() -> void { proc(param); }); } public: - pplx_dflt_scheduler() : m_pool(4) {} + pplx_dflt_scheduler() : m_pool(crossplat::threadpool::construct(4)) {} }; #endif From 86e9dd38d8d622619411661e9dc8e1268f71a6d0 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 09:29:34 -0800 Subject: [PATCH 015/438] Moved trim_whitespace and get_default_reason_phrase to be internal. --- .../include/cpprest/details/http_helpers.h | 10 ------ Release/src/CMakeLists.txt | 1 + Release/src/build/common.vcxitems | 1 + Release/src/build/common.vcxitems.filters | 1 + Release/src/http/client/http_client_asio.cpp | 1 + Release/src/http/client/http_client_msg.cpp | 1 + Release/src/http/client/http_client_winrt.cpp | 1 + Release/src/http/common/http_helpers.cpp | 20 ++--------- Release/src/http/common/http_msg.cpp | 1 + .../src/http/common/internal_http_helpers.h | 33 +++++++++++++++++++ .../src/http/listener/http_listener_msg.cpp | 1 + .../src/http/listener/http_server_asio.cpp | 1 + Release/src/websockets/client/ws_msg.cpp | 1 + .../http/utilities/http_asserts.cpp | 3 +- .../http/utilities/include/http_asserts.h | 12 +++++++ .../http/utilities/test_http_client.cpp | 4 +-- 16 files changed, 60 insertions(+), 32 deletions(-) create mode 100644 Release/src/http/common/internal_http_helpers.h diff --git a/Release/include/cpprest/details/http_helpers.h b/Release/include/cpprest/details/http_helpers.h index dd9af19577..05db40243a 100644 --- a/Release/include/cpprest/details/http_helpers.h +++ b/Release/include/cpprest/details/http_helpers.h @@ -24,16 +24,6 @@ namespace web { namespace http namespace details { - /// - /// Helper function to get the default HTTP reason phrase for a status code. - /// - utility::string_t get_default_reason_phrase(status_code code); - - // simple helper functions to trim whitespace. - _ASYNCRTIMP void __cdecl trim_whitespace(utility::string_t &str); - - bool validate_method(const utility::string_t& method); - namespace chunked_encoding { // Transfer-Encoding: chunked support diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 482b196c43..41e3423498 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -16,6 +16,7 @@ set(SOURCES http/client/http_client_msg.cpp http/client/http_client_impl.h http/client/x509_cert_utilities.cpp + http/common/internal_http_helpers.h http/common/http_helpers.cpp http/common/http_msg.cpp http/listener/http_listener.cpp diff --git a/Release/src/build/common.vcxitems b/Release/src/build/common.vcxitems index eec185f2ee..c0a0ffef1d 100644 --- a/Release/src/build/common.vcxitems +++ b/Release/src/build/common.vcxitems @@ -84,6 +84,7 @@ + diff --git a/Release/src/build/common.vcxitems.filters b/Release/src/build/common.vcxitems.filters index 35cf8139d2..eeba2e67ba 100644 --- a/Release/src/build/common.vcxitems.filters +++ b/Release/src/build/common.vcxitems.filters @@ -215,6 +215,7 @@ Header Files\private + diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 39b397c5ed..ab15490438 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -15,6 +15,7 @@ #include "stdafx.h" +#include "../common/internal_http_helpers.h" #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-local-typedef" diff --git a/Release/src/http/client/http_client_msg.cpp b/Release/src/http/client/http_client_msg.cpp index d928c0c5c4..9cab7c8da9 100644 --- a/Release/src/http/client/http_client_msg.cpp +++ b/Release/src/http/client/http_client_msg.cpp @@ -11,6 +11,7 @@ * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #include "stdafx.h" +#include "../common/internal_http_helpers.h" namespace web { namespace http { diff --git a/Release/src/http/client/http_client_winrt.cpp b/Release/src/http/client/http_client_winrt.cpp index d283b6ce93..697f48a337 100644 --- a/Release/src/http/client/http_client_winrt.cpp +++ b/Release/src/http/client/http_client_winrt.cpp @@ -15,6 +15,7 @@ #include "stdafx.h" #include "http_client_impl.h" +#include "../common/internal_http_helpers.h" #include // Important for WP8 diff --git a/Release/src/http/common/http_helpers.cpp b/Release/src/http/common/http_helpers.cpp index 7bb0636e3e..00edc3f04a 100644 --- a/Release/src/http/common/http_helpers.cpp +++ b/Release/src/http/common/http_helpers.cpp @@ -33,6 +33,8 @@ #include #endif +#include "internal_http_helpers.h" + using namespace web; using namespace utility; using namespace utility::conversions; @@ -79,24 +81,6 @@ utility::string_t get_default_reason_phrase(status_code code) return phrase; } -static void ltrim_whitespace(utility::string_t &str) -{ - size_t index; - for (index = 0; index < str.size() && isspace(str[index]); ++index); - str.erase(0, index); -} -static void rtrim_whitespace(utility::string_t &str) -{ - size_t index; - for (index = str.size(); index > 0 && isspace(str[index - 1]); --index); - str.erase(index); -} -void trim_whitespace(utility::string_t &str) -{ - ltrim_whitespace(str); - rtrim_whitespace(str); -} - size_t chunked_encoding::add_chunked_delimiters(_Out_writes_(buffer_size) uint8_t *data, _In_ size_t buffer_size, size_t bytes_read) { size_t offset = 0; diff --git a/Release/src/http/common/http_msg.cpp b/Release/src/http/common/http_msg.cpp index fd450c4ae4..6a857d7531 100644 --- a/Release/src/http/common/http_msg.cpp +++ b/Release/src/http/common/http_msg.cpp @@ -11,6 +11,7 @@ * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #include "stdafx.h" +#include "../common/internal_http_helpers.h" using namespace web; using namespace utility; diff --git a/Release/src/http/common/internal_http_helpers.h b/Release/src/http/common/internal_http_helpers.h new file mode 100644 index 0000000000..024ac84ac4 --- /dev/null +++ b/Release/src/http/common/internal_http_helpers.h @@ -0,0 +1,33 @@ +/*** +* Copyright (C) Microsoft. All rights reserved. +* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +****/ + +#pragma once + +#include "cpprest/details/basic_types.h" +#include + +namespace web { namespace http { namespace details { + +/// +/// Helper function to get the default HTTP reason phrase for a status code. +/// +utility::string_t get_default_reason_phrase(status_code code); + +// simple helper functions to trim whitespace. +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); +} + +bool validate_method(const utility::string_t& method); + +}}} diff --git a/Release/src/http/listener/http_listener_msg.cpp b/Release/src/http/listener/http_listener_msg.cpp index cfb2b533ba..82c285cfbc 100644 --- a/Release/src/http/listener/http_listener_msg.cpp +++ b/Release/src/http/listener/http_listener_msg.cpp @@ -10,6 +10,7 @@ ****/ #include "stdafx.h" +#include "../common/internal_http_helpers.h" using namespace web; using namespace utility; diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index a86c73f749..32e4f6cb69 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -22,6 +22,7 @@ #pragma clang diagnostic pop #endif +#include "../common/internal_http_helpers.h" #ifdef __ANDROID__ using utility::conversions::details::to_string; #else diff --git a/Release/src/websockets/client/ws_msg.cpp b/Release/src/websockets/client/ws_msg.cpp index aca3026a3d..10bce338e6 100644 --- a/Release/src/websockets/client/ws_msg.cpp +++ b/Release/src/websockets/client/ws_msg.cpp @@ -13,6 +13,7 @@ * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #include "stdafx.h" +#include "../../http/common/internal_http_helpers.h" #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) diff --git a/Release/tests/functional/http/utilities/http_asserts.cpp b/Release/tests/functional/http/utilities/http_asserts.cpp index bce5310a32..001d2b37a4 100644 --- a/Release/tests/functional/http/utilities/http_asserts.cpp +++ b/Release/tests/functional/http/utilities/http_asserts.cpp @@ -9,7 +9,6 @@ * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #include "stdafx.h" -#include "cpprest/details/http_helpers.h" using namespace web; using namespace utility; using namespace utility::conversions; @@ -162,7 +161,7 @@ static std::map parse_headers(utility::ist const size_t colon_index = header_line.find(U(":")); const utility::string_t header_name = header_line.substr(0, colon_index); utility::string_t header_value = header_line.substr(colon_index + 1); - web::http::details::trim_whitespace(header_value); + tests::functional::http::utilities::trim_whitespace(header_value); headers[header_name] = header_value; char c1 = (char)ss.get(), c2 = (char)ss.get(); diff --git a/Release/tests/functional/http/utilities/include/http_asserts.h b/Release/tests/functional/http/utilities/include/http_asserts.h index c561a3b5a7..02eb702b0a 100644 --- a/Release/tests/functional/http/utilities/include/http_asserts.h +++ b/Release/tests/functional/http/utilities/include/http_asserts.h @@ -18,6 +18,18 @@ namespace tests { namespace functional { namespace http { namespace utilities { +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); +} + /// /// Helper function to do percent encoding of just the '#' character, when running under WinRT. /// The WinRT http client implementation performs percent encoding on the '#'. diff --git a/Release/tests/functional/http/utilities/test_http_client.cpp b/Release/tests/functional/http/utilities/test_http_client.cpp index 516f521a4d..470c2014f5 100644 --- a/Release/tests/functional/http/utilities/test_http_client.cpp +++ b/Release/tests/functional/http/utilities/test_http_client.cpp @@ -116,8 +116,8 @@ static void parse_winhttp_headers(HINTERNET request_handle, utf16char *headersSt { utility::string_t key = header_line.substr(0, colonIndex); utility::string_t value = header_line.substr(colonIndex + 1, header_line.length() - colonIndex - 1); - web::http::details::trim_whitespace(key); - web::http::details::trim_whitespace(value); + tests::functional::http::utilities::trim_whitespace(key); + tests::functional::http::utilities::trim_whitespace(value); p_response->m_headers[key] = value; } line = wcstok_s(nullptr, U("\r\n"), &context); From ba86e292d04473b47d12bce943eed4449cadc98d Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 09:29:34 -0800 Subject: [PATCH 016/438] Add a single dummy export to each test DLL to ensure they create an import lib. --- Release/tests/functional/http/client/stdafx.cpp | 6 +++++- Release/tests/functional/http/listener/stdafx.cpp | 6 +++++- Release/tests/functional/json/stdafx.cpp | 6 +++++- Release/tests/functional/pplx/pplx_test/stdafx.cpp | 6 +++++- Release/tests/functional/streams/stdafx.cpp | 6 +++++- Release/tests/functional/uri/stdafx.cpp | 6 +++++- Release/tests/functional/utils/stdafx.cpp | 6 +++++- Release/tests/functional/websockets/client/stdafx.cpp | 6 +++++- 8 files changed, 40 insertions(+), 8 deletions(-) diff --git a/Release/tests/functional/http/client/stdafx.cpp b/Release/tests/functional/http/client/stdafx.cpp index bc2dfe733c..34ab72c03a 100644 --- a/Release/tests/functional/http/client/stdafx.cpp +++ b/Release/tests/functional/http/client/stdafx.cpp @@ -7,4 +7,8 @@ // stdafx.cpp : // Include the standard header and generate the precompiled header. -#include "stdafx.h" \ No newline at end of file +#include "stdafx.h" + +#if WIN32 +__declspec(dllexport) int httpclient_test_generate_lib = 0; +#endif \ No newline at end of file diff --git a/Release/tests/functional/http/listener/stdafx.cpp b/Release/tests/functional/http/listener/stdafx.cpp index 69ffb2b4c1..cc89710770 100644 --- a/Release/tests/functional/http/listener/stdafx.cpp +++ b/Release/tests/functional/http/listener/stdafx.cpp @@ -1,4 +1,8 @@ // stdafx.cpp : // Include the standard header and generate the precompiled header. -#include "stdafx.h" \ No newline at end of file +#include "stdafx.h" + +#if WIN32 +__declspec(dllexport) int httplistener_test_generate_lib = 0; +#endif diff --git a/Release/tests/functional/json/stdafx.cpp b/Release/tests/functional/json/stdafx.cpp index bc2dfe733c..bf3a8ed5ac 100644 --- a/Release/tests/functional/json/stdafx.cpp +++ b/Release/tests/functional/json/stdafx.cpp @@ -7,4 +7,8 @@ // stdafx.cpp : // Include the standard header and generate the precompiled header. -#include "stdafx.h" \ No newline at end of file +#include "stdafx.h" + +#if WIN32 +__declspec(dllexport) int json_test_generate_lib = 0; +#endif \ No newline at end of file diff --git a/Release/tests/functional/pplx/pplx_test/stdafx.cpp b/Release/tests/functional/pplx/pplx_test/stdafx.cpp index bc2dfe733c..5b0483c91b 100644 --- a/Release/tests/functional/pplx/pplx_test/stdafx.cpp +++ b/Release/tests/functional/pplx/pplx_test/stdafx.cpp @@ -7,4 +7,8 @@ // stdafx.cpp : // Include the standard header and generate the precompiled header. -#include "stdafx.h" \ No newline at end of file +#include "stdafx.h" + +#if WIN32 +__declspec(dllexport) int pplx_test_generate_lib = 0; +#endif diff --git a/Release/tests/functional/streams/stdafx.cpp b/Release/tests/functional/streams/stdafx.cpp index a3051268e7..027a0ecba7 100644 --- a/Release/tests/functional/streams/stdafx.cpp +++ b/Release/tests/functional/streams/stdafx.cpp @@ -8,4 +8,8 @@ // Include the standard header and generate the precompiled header. -#include "stdafx.h" \ No newline at end of file +#include "stdafx.h" + +#if WIN32 +__declspec(dllexport) int streams_test_generate_lib = 0; +#endif \ No newline at end of file diff --git a/Release/tests/functional/uri/stdafx.cpp b/Release/tests/functional/uri/stdafx.cpp index e846a95ee8..bd7d546624 100644 --- a/Release/tests/functional/uri/stdafx.cpp +++ b/Release/tests/functional/uri/stdafx.cpp @@ -8,4 +8,8 @@ // stdafx.cpp : // Include the standard header and generate the precompiled header. -#include "stdafx.h" \ No newline at end of file +#include "stdafx.h" + +#if WIN32 +__declspec(dllexport) int pplx_test_generate_lib = 0; +#endif \ No newline at end of file diff --git a/Release/tests/functional/utils/stdafx.cpp b/Release/tests/functional/utils/stdafx.cpp index e846a95ee8..1037a64c5c 100644 --- a/Release/tests/functional/utils/stdafx.cpp +++ b/Release/tests/functional/utils/stdafx.cpp @@ -8,4 +8,8 @@ // stdafx.cpp : // Include the standard header and generate the precompiled header. -#include "stdafx.h" \ No newline at end of file +#include "stdafx.h" + +#if WIN32 +__declspec(dllexport) int pplx_test_generate_lib = 0; +#endif diff --git a/Release/tests/functional/websockets/client/stdafx.cpp b/Release/tests/functional/websockets/client/stdafx.cpp index bc2dfe733c..d1bea25da0 100644 --- a/Release/tests/functional/websockets/client/stdafx.cpp +++ b/Release/tests/functional/websockets/client/stdafx.cpp @@ -7,4 +7,8 @@ // stdafx.cpp : // Include the standard header and generate the precompiled header. -#include "stdafx.h" \ No newline at end of file +#include "stdafx.h" + +#if WIN32 +__declspec(dllexport) int websocket_client_test_generate_lib = 0; +#endif \ No newline at end of file From b534b087003f99e23c1969ba5111d8e0d5728b5d Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 09:29:34 -0800 Subject: [PATCH 017/438] Suppress warnings in certain tests where they are expected. --- Release/src/websockets/client/ws_client_wspp.cpp | 4 ++++ Release/tests/functional/utils/strings.cpp | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index 7ecc3687fd..ba41dd3134 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -50,6 +50,10 @@ #endif /* __GNUC__ */ +#if defined(_MSC_VER) +#pragma warning( disable : 4503 ) +#endif + // This is a hack to avoid memory leak reports from the debug MSVC CRT for all // programs using the library: ASIO calls SSL_library_init() which calls // SSL_COMP_get_compression_methods(), which allocates some heap memory and the diff --git a/Release/tests/functional/utils/strings.cpp b/Release/tests/functional/utils/strings.cpp index 6105c1575d..80b7758083 100644 --- a/Release/tests/functional/utils/strings.cpp +++ b/Release/tests/functional/utils/strings.cpp @@ -285,6 +285,14 @@ TEST(latin1_to_utf16) } } +#if defined(_MSC_VER) +#pragma warning(disable : 4996) +#elif defined(__clang__) +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + TEST(print_string_locale, "Ignore:Android", "Locale unsupported on Android") { std::locale changedLocale; From 6b72090ae080e6bfc75a554ef221bbf1d2850cb3 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 09:29:34 -0800 Subject: [PATCH 018/438] Add docs/ to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d0ff65b0ac..cdab0c784b 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,4 @@ Intermediate/ .vs/ # Ignore cmake building directories build.*/ +docs/ \ No newline at end of file From 3dc2b4265ebfaea848f46198b2bd6935b4b598e1 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 17:00:07 -0800 Subject: [PATCH 019/438] Improve consistency of string_t vs std::string inside the ASIO implementation. --- .../cpprest/details/http_server_asio.h | 1 + Release/include/cpprest/http_headers.h | 9 +++- .../BlackJack/BlackJack_Server/stdafx.h | 12 +++-- Release/src/http/client/http_client_asio.cpp | 36 +++++++------- Release/src/http/common/http_helpers.cpp | 4 +- .../src/http/listener/http_server_asio.cpp | 48 ++++++++++++------- .../http/utilities/test_http_server.cpp | 10 ++-- 7 files changed, 73 insertions(+), 47 deletions(-) diff --git a/Release/include/cpprest/details/http_server_asio.h b/Release/include/cpprest/details/http_server_asio.h index b7b1edc162..4ad37f404b 100644 --- a/Release/include/cpprest/details/http_server_asio.h +++ b/Release/include/cpprest/details/http_server_asio.h @@ -19,6 +19,7 @@ #pragma clang diagnostic pop #endif #include +#include namespace web { diff --git a/Release/include/cpprest/http_headers.h b/Release/include/cpprest/http_headers.h index 4c7af7cf27..2458872410 100644 --- a/Release/include/cpprest/http_headers.h +++ b/Release/include/cpprest/http_headers.h @@ -306,9 +306,14 @@ class http_headers return true; } - bool bind_impl(const key_type &text, ::utility::string_t &ref) const + bool bind_impl(const key_type &text, utf16string &ref) const { - ref = text; + ref = utility::conversions::to_utf16string(text); + return true; + } + bool bind_impl(const key_type &text, std::string &ref) const + { + ref = utility::conversions::to_utf8string(text); return true; } diff --git a/Release/samples/BlackJack/BlackJack_Server/stdafx.h b/Release/samples/BlackJack/BlackJack_Server/stdafx.h index 15f4ceb58f..c91d64d219 100644 --- a/Release/samples/BlackJack/BlackJack_Server/stdafx.h +++ b/Release/samples/BlackJack/BlackJack_Server/stdafx.h @@ -22,14 +22,16 @@ #include #include +#include "cpprest/json.h" +#include "cpprest/http_listener.h" +#include "cpprest/uri.h" +#include "cpprest/asyncrt_utils.h" + #ifdef _WIN32 +#ifndef NOMINMAX #define NOMINMAX +#endif #include #else # include #endif - -#include "cpprest/json.h" -#include "cpprest/http_listener.h" -#include "cpprest/uri.h" -#include "cpprest/asyncrt_utils.h" diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index ab15490438..a2c7f17281 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -15,7 +15,9 @@ #include "stdafx.h" +#include "cpprest/asyncrt_utils.h" #include "../common/internal_http_helpers.h" + #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-local-typedef" @@ -25,6 +27,7 @@ #include #include #include +#include #if defined(__clang__) #pragma clang diagnostic pop #endif @@ -33,6 +36,7 @@ #error "Cpp rest SDK requires c++11 smart pointer support from boost" #endif +#include "pplx/threadpool.h" #include "http_client_impl.h" #include "cpprest/base_uri.h" #include "cpprest/details/x509_cert_utilities.h" @@ -144,7 +148,7 @@ class asio_connection template void async_handshake(boost::asio::ssl::stream_base::handshake_type type, const http_client_config &config, - const utility::string_t &host_name, + const std::string& host_name, const HandshakeHandler &handshake_handler, const CertificateHandler &cert_handler) { @@ -352,7 +356,7 @@ class asio_client final : public _http_client_communicator : _http_client_communicator(std::move(address), std::move(client_config)) , m_resolver(crossplat::threadpool::shared_instance().service()) , m_pool(std::make_shared()) - , m_start_with_ssl(base_uri().scheme() == "https" && !this->client_config().proxy().is_specified()) + , m_start_with_ssl(base_uri().scheme() == U("https") && !this->client_config().proxy().is_specified()) {} void send_request(const std::shared_ptr &request_ctx) override; @@ -436,7 +440,7 @@ class asio_context : public request_context, public std::enable_shared_from_this int proxy_port = proxy_uri.port() == -1 ? 8080 : proxy_uri.port(); const auto &base_uri = m_context->m_http_client->base_uri(); - const auto &host = base_uri.host(); + const auto &host = utility::conversions::to_utf8string(base_uri.host()); std::ostream request_stream(&m_request); request_stream.imbue(std::locale::classic()); @@ -600,7 +604,7 @@ class asio_context : public request_context, public std::enable_shared_from_this } http_proxy_type proxy_type = http_proxy_type::none; - utility::string_t proxy_host; + std::string proxy_host; int proxy_port = -1; // There is no support for auto-detection of proxies on non-windows platforms, it must be specified explicitly from the client code. @@ -610,7 +614,7 @@ class asio_context : public request_context, public std::enable_shared_from_this auto proxy = m_http_client->client_config().proxy(); auto proxy_uri = proxy.address(); proxy_port = proxy_uri.port() == -1 ? 8080 : proxy_uri.port(); - proxy_host = proxy_uri.host(); + proxy_host = utility::conversions::to_utf8string(proxy_uri.host()); } auto start_http_request_flow = [proxy_type, proxy_host, proxy_port](std::shared_ptr ctx) @@ -627,9 +631,9 @@ class asio_context : public request_context, public std::enable_shared_from_this // For a normal http proxy, we need to specify the full request uri, otherwise just specify the resource auto encoded_resource = proxy_type == http_proxy_type::http ? full_uri.to_string() : full_uri.resource().to_string(); - if (encoded_resource == "") + if (encoded_resource.empty()) { - encoded_resource = "/"; + encoded_resource = U("/"); } const auto &method = ctx->m_request.method(); @@ -645,9 +649,9 @@ class asio_context : public request_context, public std::enable_shared_from_this std::ostream request_stream(&ctx->m_body_buf); request_stream.imbue(std::locale::classic()); - const auto &host = base_uri.host(); + const auto &host = utility::conversions::to_utf8string(base_uri.host()); - request_stream << method << " " << encoded_resource << " " << "HTTP/1.1" << CRLF; + request_stream << utility::conversions::to_utf8string(method) << " " << utility::conversions::to_utf8string(encoded_resource) << " " << "HTTP/1.1" << CRLF; int port = base_uri.port(); @@ -705,7 +709,7 @@ class asio_context : public request_context, public std::enable_shared_from_this "Pragma: no-cache\r\n"); } - request_stream << ::web::http::details::flatten_http_headers(ctx->m_request.headers()); + request_stream << utility::conversions::to_utf8string(::web::http::details::flatten_http_headers(ctx->m_request.headers())); request_stream << extra_headers; // Enforce HTTP connection keep alive (even for the old HTTP/1.0 protocol). request_stream << "Connection: Keep-Alive" << CRLF << CRLF; @@ -796,7 +800,7 @@ class asio_context : public request_context, public std::enable_shared_from_this return header; } - void report_error(const utility::string_t &message, const boost::system::error_code &ec, httpclient_errorcode_context context = httpclient_errorcode_context::none) + void report_error(const std::string &message, const boost::system::error_code &ec, httpclient_errorcode_context context = httpclient_errorcode_context::none) { // By default, errorcodeValue don't need to converted long errorcodeValue = ec.value(); @@ -844,7 +848,7 @@ class asio_context : public request_context, public std::enable_shared_from_this { write_request(); } - else if (ec.value() == boost::system::errc::operation_canceled) + else if (ec.value() == boost::system::errc::operation_canceled || ec.value() == boost::asio::error::operation_aborted) { request_context::report_error(ec.value(), "Request canceled by user."); } @@ -891,7 +895,7 @@ class asio_context : public request_context, public std::enable_shared_from_this const auto weakCtx = std::weak_ptr(shared_from_this()); m_connection->async_handshake(boost::asio::ssl::stream_base::client, m_http_client->client_config(), - m_http_client->base_uri().host(), + utility::conversions::to_utf8string(m_http_client->base_uri().host()), boost::bind(&asio_context::handle_handshake, shared_from_this(), boost::asio::placeholders::error), // Use a weak_ptr since the verify_callback is stored until the connection is destroyed. @@ -932,7 +936,7 @@ class asio_context : public request_context, public std::enable_shared_from_this // certificate chain, the rest are optional intermediate certificates, followed // finally by the root CA self signed certificate. - const auto &host = m_http_client->base_uri().host(); + const auto &host = utility::conversions::to_utf8string(m_http_client->base_uri().host()); #if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) // On OS X, iOS, and Android, OpenSSL doesn't have access to where the OS // stores keychains. If OpenSSL fails we will doing verification at the @@ -1125,7 +1129,7 @@ class asio_context : public request_context, public std::enable_shared_from_this m_response.set_status_code(status_code); ::web::http::details::trim_whitespace(status_message); - m_response.set_reason_phrase(std::move(status_message)); + m_response.set_reason_phrase(utility::conversions::to_string_t(std::move(status_message))); if (!response_stream || http_version.substr(0, 5) != "HTTP/") { @@ -1195,7 +1199,7 @@ class asio_context : public request_context, public std::enable_shared_from_this m_connection->set_keep_alive(!boost::iequals(value, U("close"))); } - m_response.headers().add(std::move(name), std::move(value)); + m_response.headers().add(utility::conversions::to_string_t(std::move(name)), utility::conversions::to_string_t(std::move(value))); } } complete_headers(); diff --git a/Release/src/http/common/http_helpers.cpp b/Release/src/http/common/http_helpers.cpp index 00edc3f04a..2c45e5961d 100644 --- a/Release/src/http/common/http_helpers.cpp +++ b/Release/src/http/common/http_helpers.cpp @@ -114,8 +114,7 @@ size_t chunked_encoding::add_chunked_delimiters(_Out_writes_(buffer_size) uint8_ return offset; } -#if (!defined(_WIN32) || defined(__cplusplus_winrt)) -const std::array valid_chars = +static const std::array valid_chars = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0-15 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //16-31 @@ -142,7 +141,6 @@ bool validate_method(const utility::string_t& method) return true; } -#endif namespace compression { diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 32e4f6cb69..7b6f7dd6e9 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -14,6 +14,7 @@ */ #include "stdafx.h" #include +#include #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wcast-align" @@ -22,12 +23,16 @@ #pragma clang diagnostic pop #endif +#include "cpprest/details/http_server_asio.h" +#include "cpprest/asyncrt_utils.h" #include "../common/internal_http_helpers.h" + #ifdef __ANDROID__ using utility::conversions::details::to_string; #else using std::to_string; #endif + using namespace boost::asio; using namespace boost::asio::ip; @@ -266,8 +271,16 @@ void connection::handle_http_line(const boost::system::error_code& ec) request_stream.imbue(std::locale::classic()); std::skipws(request_stream); - std::string http_verb; + web::http::method http_verb; +#ifndef _UTF16_STRINGS request_stream >> http_verb; +#else + { + std::string tmp; + request_stream >> tmp; + http_verb = utility::conversions::latin1_to_utf16(tmp); + } +#endif if (boost::iequals(http_verb, http::methods::GET)) http_verb = http::methods::GET; else if (boost::iequals(http_verb, http::methods::POST)) http_verb = http::methods::POST; @@ -305,7 +318,7 @@ void connection::handle_http_line(const boost::system::error_code& ec) // Get the path - remove the version portion and prefix space try { - m_request.set_request_uri(http_path_and_version.substr(1, http_path_and_version.size() - VersionPortionSize - 1)); + m_request.set_request_uri(utility::conversions::to_string_t(http_path_and_version.substr(1, http_path_and_version.size() - VersionPortionSize - 1))); } catch(const uri_exception &e) { @@ -332,24 +345,26 @@ void connection::handle_headers() std::istream request_stream(&m_request_buf); request_stream.imbue(std::locale::classic()); std::string header; + + auto& headers = m_request.headers(); + while (std::getline(request_stream, header) && header != "\r") { auto colon = header.find(':'); if (colon != std::string::npos && colon != 0) { - auto name = header.substr(0, colon); - auto value = header.substr(colon + 1, header.length() - (colon + 1)); // also exclude '\r' + auto name = utility::conversions::to_string_t(header.substr(0, colon)); + auto value = utility::conversions::to_string_t(header.substr(colon + 1, header.length() - (colon + 1))); // also exclude '\r' http::details::trim_whitespace(name); http::details::trim_whitespace(value); - auto& currentValue = m_request.headers()[name]; - if (currentValue.empty() || boost::iequals(name, header_names::content_length)) // (content-length is already set) + if (boost::iequals(name, header_names::content_length)) { - currentValue = value; + headers[http::header_names::content_length] = value; } else { - currentValue += U(", ") + value; + headers.add(name, value); } } else @@ -549,7 +564,7 @@ void connection::dispatch_request_to_listener() std::string path = ""; for (size_t j = 0; j < static_cast(i); ++j) { - path += "/" + path_segments[j]; + path += "/" + utility::conversions::to_utf8string(path_segments[j]); } path += "/"; @@ -643,7 +658,7 @@ void connection::async_process_response(http_response response) os.imbue(std::locale::classic()); os << "HTTP/1.1 " << response.status_code() << " " - << response.reason_phrase() + << utility::conversions::to_utf8string(response.reason_phrase()) << CRLF; m_chunked = false; @@ -674,7 +689,7 @@ void connection::async_process_response(http_response response) m_close = true; } } - os << header.first << ": " << header.second << CRLF; + os << utility::conversions::to_utf8string(header.first) << ": " << utility::conversions::to_utf8string(header.second) << CRLF; } os << CRLF; @@ -875,18 +890,19 @@ pplx::task http_linux_server::stop() std::pair canonical_parts(const http::uri& uri) { - std::ostringstream endpoint; - endpoint.imbue(std::locale::classic()); - endpoint << uri::decode(uri.host()) << ":" << uri.port(); + std::string endpoint; + endpoint += utility::conversions::to_utf8string(uri::decode(uri.host())); + endpoint += ":"; + endpoint += to_string(uri.port()); - auto path = uri::decode(uri.path()); + auto path = utility::conversions::to_utf8string(uri::decode(uri.path())); if (path.size() > 1 && path[path.size()-1] != '/') { path += "/"; // ensure the end slash is present } - return std::make_pair(endpoint.str(), path); + return std::make_pair(std::move(endpoint), std::move(path)); } pplx::task http_linux_server::register_listener(details::http_listener_impl* listener) diff --git a/Release/tests/functional/http/utilities/test_http_server.cpp b/Release/tests/functional/http/utilities/test_http_server.cpp index 3ab807d903..2eb8302c86 100644 --- a/Release/tests/functional/http/utilities/test_http_server.cpp +++ b/Release/tests/functional/http/utilities/test_http_server.cpp @@ -478,7 +478,7 @@ class _test_http_server class _test_http_server { private: - const std::string m_uri; + const utility::string_t m_uri; typename web::http::experimental::listener::http_listener m_listener; pplx::extensibility::critical_section_t m_lock; std::vector> m_requests; @@ -500,8 +500,8 @@ class _test_http_server auto tr = new test_request(); tr->m_method = result.method(); tr->m_path = result.request_uri().resource().to_string(); - if (tr->m_path == "") - tr->m_path = "/"; + if (tr->m_path.empty()) + tr->m_path = U("/"); tr->m_p_server = this; tr->m_request_id = ++m_last_request_id; @@ -592,7 +592,7 @@ class _test_http_server std::vector> next_requests(const size_t count) { std::vector> result; - for (int i = 0; i < count; ++i) + for (size_t i = 0; i < count; ++i) { result.push_back(next_request()); } @@ -602,7 +602,7 @@ class _test_http_server std::vector wait_for_requests(const size_t count) { std::vector requests; - for (int i = 0; i < count; ++i) + for (size_t i = 0; i < count; ++i) { requests.push_back(wait_for_request()); } From 38c86e206ccd0ef5d4afd511ac1d094b63af6a4b Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 17:02:46 -0800 Subject: [PATCH 020/438] Add macros to _very experimentally_ enable building ASIO on Windows. --- Release/include/cpprest/http_client.h | 8 ++++---- Release/include/cpprest/http_listener.h | 14 +++++++------- Release/src/http/listener/http_server_api.cpp | 2 +- Release/src/pch/stdafx.h | 2 +- .../functional/http/utilities/test_http_client.cpp | 1 + .../functional/http/utilities/test_http_server.cpp | 5 +++-- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Release/include/cpprest/http_client.h b/Release/include/cpprest/http_client.h index 1f26e075ce..f0743d2874 100644 --- a/Release/include/cpprest/http_client.h +++ b/Release/include/cpprest/http_client.h @@ -45,7 +45,7 @@ typedef void* native_handle;}}} #include "cpprest/oauth2.h" -#if !defined(_WIN32) && !defined(__cplusplus_winrt) +#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO) #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" @@ -88,7 +88,7 @@ class http_client_config , m_validate_certificates(true) #endif , m_set_user_nativehandle_options([](native_handle)->void{}) -#if !defined(_WIN32) && !defined(__cplusplus_winrt) +#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO) , m_tlsext_sni_enabled(true) #endif #if defined(_WIN32) && !defined(__cplusplus_winrt) @@ -338,7 +338,7 @@ class http_client_config m_set_user_nativehandle_options(handle); } -#if !defined(_WIN32) && !defined(__cplusplus_winrt) +#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO) /// /// Sets a callback to enable custom setting of the ssl context, at construction time. /// @@ -398,7 +398,7 @@ class http_client_config std::function m_set_user_nativehandle_options; -#if !defined(_WIN32) && !defined(__cplusplus_winrt) +#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO) std::function m_ssl_context_callback; bool m_tlsext_sni_enabled; #endif diff --git a/Release/include/cpprest/http_listener.h b/Release/include/cpprest/http_listener.h index 1ff260bbfc..3c154e49a6 100644 --- a/Release/include/cpprest/http_listener.h +++ b/Release/include/cpprest/http_listener.h @@ -17,7 +17,7 @@ #include #include "cpprest/http_msg.h" -#if !defined(_WIN32) && !defined(__cplusplus_winrt) +#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) #include #endif @@ -54,7 +54,7 @@ class http_listener_config /// http_listener_config to copy. http_listener_config(const http_listener_config &other) : m_timeout(other.m_timeout) -#ifndef _WIN32 +#if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) , m_ssl_context_callback(other.m_ssl_context_callback) #endif {} @@ -65,7 +65,7 @@ class http_listener_config /// http_listener_config to move from. http_listener_config(http_listener_config &&other) : m_timeout(std::move(other.m_timeout)) -#ifndef _WIN32 +#if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) , m_ssl_context_callback(std::move(other.m_ssl_context_callback)) #endif {} @@ -79,7 +79,7 @@ class http_listener_config if(this != &rhs) { m_timeout = rhs.m_timeout; -#ifndef _WIN32 +#if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) m_ssl_context_callback = rhs.m_ssl_context_callback; #endif } @@ -95,7 +95,7 @@ class http_listener_config if(this != &rhs) { m_timeout = std::move(rhs.m_timeout); -#ifndef _WIN32 +#if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) m_ssl_context_callback = std::move(rhs.m_ssl_context_callback); #endif } @@ -120,7 +120,7 @@ class http_listener_config m_timeout = std::move(timeout); } -#ifndef _WIN32 +#if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) /// /// Get the callback of ssl context /// @@ -143,7 +143,7 @@ class http_listener_config private: utility::seconds m_timeout; -#ifndef _WIN32 +#if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) std::function m_ssl_context_callback; #endif }; diff --git a/Release/src/http/listener/http_server_api.cpp b/Release/src/http/listener/http_server_api.cpp index 9c0fefcef2..28c071fe1f 100644 --- a/Release/src/http/listener/http_server_api.cpp +++ b/Release/src/http/listener/http_server_api.cpp @@ -72,7 +72,7 @@ pplx::task http_server_api::register_listener(_In_ web::http::experimental // the server API was not initialized, register a default if(s_server_api == nullptr) { -#ifdef _WIN32 +#if defined(_WIN32) && !defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) std::unique_ptr server_api(new http_windows_server()); #else std::unique_ptr server_api(new http_linux_server()); diff --git a/Release/src/pch/stdafx.h b/Release/src/pch/stdafx.h index f060dba5fe..ee7ba0e70f 100644 --- a/Release/src/pch/stdafx.h +++ b/Release/src/pch/stdafx.h @@ -138,7 +138,7 @@ #include "cpprest/details/http_server_api.h" #endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA -#ifdef _WIN32 +#if defined(_WIN32) && !defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) #if _WIN32_WINNT >= _WIN32_WINNT_VISTA #include "cpprest/details/http_server_httpsys.h" #endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA diff --git a/Release/tests/functional/http/utilities/test_http_client.cpp b/Release/tests/functional/http/utilities/test_http_client.cpp index 470c2014f5..ab188f7b60 100644 --- a/Release/tests/functional/http/utilities/test_http_client.cpp +++ b/Release/tests/functional/http/utilities/test_http_client.cpp @@ -16,6 +16,7 @@ #include "test_http_client.h" #ifdef _WIN32 #include +#pragma comment(lib, "winhttp.lib") #pragma warning ( push ) #pragma warning ( disable : 4457 ) #include diff --git a/Release/tests/functional/http/utilities/test_http_server.cpp b/Release/tests/functional/http/utilities/test_http_server.cpp index 2eb8302c86..3e6767f239 100644 --- a/Release/tests/functional/http/utilities/test_http_server.cpp +++ b/Release/tests/functional/http/utilities/test_http_server.cpp @@ -12,6 +12,7 @@ #ifdef _WIN32 #include +#pragma comment(lib, "httpapi.lib") #pragma warning ( push ) #pragma warning ( disable : 4457 ) #include @@ -31,7 +32,7 @@ using namespace utility::conversions; namespace tests { namespace functional { namespace http { namespace utilities { -#ifdef _WIN32 +#if defined(_WIN32) // Helper function to parse verb from Windows HTTP Server API. static utility::string_t parse_verb(const HTTP_REQUEST *p_http_request) { @@ -647,7 +648,7 @@ unsigned long test_request::reply( return reply_impl(status_code, reason_phrase, headers, (void *)&data[0], data.size() * sizeof(utf16char)); } -#ifdef _WIN32 +#if defined(_WIN32) unsigned long test_request::reply_impl( const unsigned short status_code, const utility::string_t &reason_phrase, From c07dfff3e8c96e046216b3b5609abe9698380328 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 17:05:38 -0800 Subject: [PATCH 021/438] Stop internal http_server_api when all paths have been deregistered. This forces all outstanding requests to have their connections severed, enabling the tests to continue. --- Release/src/http/listener/http_server_api.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Release/src/http/listener/http_server_api.cpp b/Release/src/http/listener/http_server_api.cpp index 28c071fe1f..3e64a2dfcf 100644 --- a/Release/src/http/listener/http_server_api.cpp +++ b/Release/src/http/listener/http_server_api.cpp @@ -106,6 +106,7 @@ pplx::task http_server_api::register_listener(_In_ web::http::experimental try { server_api()->stop().wait(); + http_server_api::unsafe_register_server_api(nullptr); } catch(...) { // ignore this exception since we want to report the original one @@ -138,11 +139,12 @@ pplx::task http_server_api::unregister_listener(_In_ web::http::experiment if (pplx::details::atomic_decrement(s_registrations) == 0L) { server_api()->stop().wait(); + http_server_api::unsafe_register_server_api(nullptr); } } catch(...) { // save the original exception from unregister listener - if(except != nullptr) + if(except == nullptr) { except = std::current_exception(); } From 13c607a22cdc9e5c9c1d20049ee3ec5f7a05405b Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 17:06:25 -0800 Subject: [PATCH 022/438] Clean up use of owning raw pointer with RAII. --- .../src/http/listener/http_server_asio.cpp | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 7b6f7dd6e9..9ec7c66b6f 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -221,23 +221,19 @@ void connection::start_request_response() void hostport_listener::on_accept(ip::tcp::socket* socket, const boost::system::error_code& ec) { - if (ec) - { - delete socket; - } - else + std::unique_ptr usocket(std::move(socket)); + + if (!ec) { std::lock_guard lock(m_connections_lock); - { - m_connections.insert(new connection(std::unique_ptr(std::move(socket)), m_p_server, this, m_is_https, m_ssl_context_callback)); - m_all_connections_complete.reset(); + m_connections.insert(new connection(std::move(usocket), m_p_server, this, m_is_https, m_ssl_context_callback)); + m_all_connections_complete.reset(); - if (m_acceptor) - { - // spin off another async accept - auto newSocket = new ip::tcp::socket(crossplat::threadpool::shared_instance().service()); - m_acceptor->async_accept(*newSocket, boost::bind(&hostport_listener::on_accept, this, newSocket, placeholders::error)); - } + if (m_acceptor) + { + // spin off another async accept + auto newSocket = new ip::tcp::socket(crossplat::threadpool::shared_instance().service()); + m_acceptor->async_accept(*newSocket, boost::bind(&hostport_listener::on_accept, this, newSocket, placeholders::error)); } } } From 7a9b20a597b472b2b0823c8a181e9db1905280d9 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 17:15:48 -0800 Subject: [PATCH 023/438] Remove duplicate test --- .../http/listener/reply_helper_tests.cpp | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/Release/tests/functional/http/listener/reply_helper_tests.cpp b/Release/tests/functional/http/listener/reply_helper_tests.cpp index dc22c59037..d7a8ef5f29 100644 --- a/Release/tests/functional/http/listener/reply_helper_tests.cpp +++ b/Release/tests/functional/http/listener/reply_helper_tests.cpp @@ -91,30 +91,6 @@ TEST_FIXTURE(uri_address, string) listener.close().wait(); } -TEST_FIXTURE(uri_address, multiple_responses_to_request) -{ - http_listener listener(m_uri); - listener.open().wait(); - test_http_client::scoped_client client(m_uri); - test_http_client * p_client = client.client(); - - listener.support([](http_request request) - { - http_response response(status_codes::OK); - request.reply(response).wait(); - - // try responding to the request again - VERIFY_THROWS(request.reply(response).wait(), http_exception); - }); - VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U(""))); - p_client->next_response().then([&](test_response *p_response) - { - http_asserts::assert_test_response_equals(p_response, status_codes::OK); - }).wait(); - - listener.close().wait(); -} - } }}}} \ No newline at end of file From cfff33cb3c3aa1bf8defc08a0ecf6239bfb214e5 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 17:18:45 -0800 Subject: [PATCH 024/438] Always send Content-Length if not using Transfer-Encoding: chunked. --- Release/src/http/client/http_client_asio.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index a2c7f17281..107a41f82d 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -700,6 +700,11 @@ class asio_context : public request_context, public std::enable_shared_from_this ctx->m_needChunked = true; extra_headers.append("Transfer-Encoding:chunked\r\n"); } + else + { + // Howver, if there is no body, then just send 0 length. + extra_headers.append("Content-Length: 0\r\n"); + } } if (proxy_type == http_proxy_type::http) From 508e3d35d0c365f8346c741e35436e7b1dc7ecb9 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 12 Dec 2016 17:19:26 -0800 Subject: [PATCH 025/438] Improve test performance --- .../tests/functional/http/client/connections_and_errors.cpp | 6 ++++-- Release/tests/functional/pplx/pplx_test/pplxtask_tests.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Release/tests/functional/http/client/connections_and_errors.cpp b/Release/tests/functional/http/client/connections_and_errors.cpp index 251dc3ce51..9bbd4e626a 100644 --- a/Release/tests/functional/http/client/connections_and_errors.cpp +++ b/Release/tests/functional/http/client/connections_and_errors.cpp @@ -407,7 +407,9 @@ TEST_FIXTURE(uri_address, cancel_bad_port) web::http::uri uri(U("https://microsoft.com:442/")); // Send request. - http_client c(uri); + http_client_config config; + config.set_timeout(std::chrono::milliseconds(500)); + http_client c(uri, config); web::http::http_request r; auto cts = pplx::cancellation_token_source(); auto ct = cts.get_token(); @@ -415,7 +417,7 @@ TEST_FIXTURE(uri_address, cancel_bad_port) // Make sure that the client already finished resolving before canceling, // otherwise the bug might not be triggered. - std::this_thread::sleep_for(std::chrono::seconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(400)); cts.cancel(); VERIFY_THROWS_HTTP_ERROR_CODE(t.get(), std::errc::operation_canceled); diff --git a/Release/tests/functional/pplx/pplx_test/pplxtask_tests.cpp b/Release/tests/functional/pplx/pplx_test/pplxtask_tests.cpp index a87abe1aa2..a1f6580edf 100644 --- a/Release/tests/functional/pplx/pplx_test/pplxtask_tests.cpp +++ b/Release/tests/functional/pplx/pplx_test/pplxtask_tests.cpp @@ -130,7 +130,7 @@ SUITE(pplxtask_tests) TEST(TestCancellationTokenRegression) { - for (int i=0; i < 10000; i++) + for (int i=0; i < 500; i++) { task_completion_event tce; task starter(tce); From c1c673df776e05c456a3794f080276ef2a054702 Mon Sep 17 00:00:00 2001 From: Hannes Rantzsch Date: Wed, 14 Dec 2016 15:05:08 +0100 Subject: [PATCH 026/438] add *.hpp and *.dat HEADERS_DETAILS to CMake file globbing --- Release/src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 41e3423498..44d50407af 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_policy(SET CMP0022 NEW) file(GLOB HEADERS_CPPREST "../include/cpprest/*.h" "../include/cpprest/*.hpp" "../include/cpprest/*.dat") file(GLOB HEADERS_PPLX "../include/pplx/*.h" "../include/pplx/*.hpp") -file(GLOB HEADERS_DETAILS "../include/cpprest/details/*.h" "../include/pplx/*.hpp" "../include/pplx/*.dat") +file(GLOB HEADERS_DETAILS "../include/cpprest/details/*.h" "../include/cpprest/details/*.hpp" "../include/cpprest/details/*.dat" "../include/pplx/*.hpp" "../include/pplx/*.dat") source_group("Header Files\\cpprest" FILES ${HEADERS_CPPREST}) source_group("Header Files\\pplx" FILES ${HEADERS_PPLX}) source_group("Header Files\\cpprest\\details" FILES ${HEADERS_DETAILS}) From 1881d549e65b5c9e915d72a597f99e92d07f5c86 Mon Sep 17 00:00:00 2001 From: Holger Strauss Date: Tue, 27 Dec 2016 11:58:45 +0100 Subject: [PATCH 027/438] Paths in Post-Build Event quoted to allow compilation in folders with a spaces in the path. --- Release/src/build/vs14.uwp/cpprestsdk140.uwp.vcxproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Release/src/build/vs14.uwp/cpprestsdk140.uwp.vcxproj b/Release/src/build/vs14.uwp/cpprestsdk140.uwp.vcxproj index 8a5cd6e499..88a336088c 100644 --- a/Release/src/build/vs14.uwp/cpprestsdk140.uwp.vcxproj +++ b/Release/src/build/vs14.uwp/cpprestsdk140.uwp.vcxproj @@ -69,10 +69,10 @@ - _ASYNCRT_EXPORT;_PPLX_EXPORT;_USRDLL;%(PreprocessorDefinitions); + _ASYNCRT_EXPORT;_PPLX_EXPORT;_USRDLL;%(PreprocessorDefinitions); Use true - $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;%(AdditionalIncludeDirectories) + $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;%(AdditionalIncludeDirectories) Use stdafx.h -Zm250 /bigobj %(AdditionalOptions) @@ -81,15 +81,15 @@ Console false - UseLinkTimeCodeGeneration + UseLinkTimeCodeGeneration false - copy /Y $(OutDir)\* $(OutDir)..\ - link /edit /appcontainer:no $(OutDir)..\$(TargetName).dll + copy /Y "$(OutDir)\*" "$(OutDir)..\" + link /edit /appcontainer:no "$(OutDir)..\$(TargetName).dll" exit 0 Copying $(TargetName).winrt binaries to OutDir and removing appcontainer flag From 4aa1b6db7a7181a2a7c9d8e0c42a26e05d11e25d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Meusel?= Date: Thu, 19 Jan 2017 11:02:35 +0100 Subject: [PATCH 028/438] FIX: don't add default port to 'Host' header (ASIO) If requesting data through a pre-signed S3 URL [1], the signature includes the hostname provided in the 'Host' header. Appending a default port invalidates the signature. --- Release/src/http/client/http_client_asio.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index ab15490438..3d3a72545d 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -659,7 +659,11 @@ class asio_context : public request_context, public std::enable_shared_from_this // Add the Host header if user has not specified it explicitly if (!ctx->m_request.headers().has(header_names::host)) { - request_stream << "Host: " << host << ":" << port << CRLF; + request_stream << "Host: " << host; + if (!base_uri.is_port_default()) { + request_stream << ":" << port; + } + request_stream << CRLF; } // Extra request headers are constructed here. From dcce40b51272c8a422695e8efaeab647403ebcb9 Mon Sep 17 00:00:00 2001 From: pnemere Date: Thu, 23 Feb 2017 09:31:18 +1000 Subject: [PATCH 029/438] Use 1.0.2k openssl library - Play store rejects 1.0.2d On Android we need a newer openssl library otherwise this nuget package is pretty much useless. Play store scans and somehow finds compiled 1.0.2d in binary and rejects the upload. --- Build_android/openssl/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Build_android/openssl/Makefile b/Build_android/openssl/Makefile index f0bc60591d..71a992164d 100644 --- a/Build_android/openssl/Makefile +++ b/Build_android/openssl/Makefile @@ -1,5 +1,5 @@ SHELL := /bin/bash -OPENSSL_VER = openssl-1.0.2d +OPENSSL_VER = openssl-1.0.2k all: armeabi-v7a/lib/libssl.a x86/lib/libssl.a From e89add82c9e41b9ab01a662da76ba74a1aa356f6 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Fri, 24 Feb 2017 16:49:39 -0800 Subject: [PATCH 030/438] Update README.md --- README.md | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9b68329ab1..308fd071b8 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,25 @@ The C++ REST SDK is a Microsoft project for cloud-based client-server communicat ## Getting Started -Are you new to the C++ Rest SDK? To get going we recommend you start by taking a look at our [tutorial](https://github.com/Microsoft/cpprestsdk/wiki/Getting-Started-Tutorial) to use the http_client. It walks through how to setup a project to use the C++ Rest SDK and make a basic Http request. Other important information, like how to build the C++ Rest SDK from source, can be located on the [documentation](https://github.com/Microsoft/cpprestsdk/wiki) page. +With [vcpkg](https://github.com/Microsoft/vcpkg) on Windows +``` +PS> vcpkg install cpprestsdk cpprestsdk:x64-windows +``` +With [apt-get](https://launchpad.net/ubuntu/+source/casablanca/2.8.0-2build2) on Debian/Ubuntu +``` +$ sudo apt-get install libcpprest-dev +``` +With [brew](https://github.com/Homebrew/homebrew-core/blob/master/Formula/cpprestsdk.rb) on OSX +``` +$ brew install cpprestsdk +``` +With [NuGet](https://www.nuget.org/packages/cpprestsdk.android/) on Windows for Android +``` +PM> Install-Package cpprestsdk.android +``` +For other platforms, install options, how to build from source, and more, take a look at our [Documentation](https://github.com/Microsoft/cpprestsdk/wiki). + +Once you have the library, look at our [tutorial](https://github.com/Microsoft/cpprestsdk/wiki/Getting-Started-Tutorial) to use the http_client. It walks through how to setup a project to use the C++ Rest SDK and make a basic Http request. ## What's in the SDK: @@ -31,4 +49,4 @@ We'd love to get your review score, whether good or bad, but even more than that * [Issue Tracker](https://github.com/Microsoft/cpprestsdk/issues) * Directly contact us: -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. \ No newline at end of file +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. From 0898d5c771d8f70e524a022f217fa2b017be6029 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Mon, 6 Mar 2017 13:38:24 +0100 Subject: [PATCH 031/438] add support to customize the session handle --- Release/include/cpprest/http_client.h | 28 +++++++++++++++++++ .../src/http/client/http_client_winhttp.cpp | 10 +++++++ 2 files changed, 38 insertions(+) diff --git a/Release/include/cpprest/http_client.h b/Release/include/cpprest/http_client.h index 1f26e075ce..01da04b755 100644 --- a/Release/include/cpprest/http_client.h +++ b/Release/include/cpprest/http_client.h @@ -312,6 +312,33 @@ class http_client_config } #endif + /// + /// Sets a callback to enable custom setting of platform specific options. + /// + /// + /// The native_handle is the following type depending on the underlying platform: + /// Windows Desktop, WinHTTP - HINTERNET + /// Windows Runtime, WinRT - IXMLHTTPRequest2 * + /// All other platforms, Boost.Asio: + /// https - boost::asio::ssl::stream * + /// http - boost::asio::ip::tcp::socket * + /// + /// A user callback allowing for customization of the session + void set_nativesessionhandle_options(const std::function &callback) + { + m_set_user_nativesessionhandle_options = callback; + } + + /// + /// Invokes a user's callback to allow for customization of the session. + /// + /// A internal implementation handle. + void invoke_nativesessionhandle_options(native_handle handle) const + { + m_set_user_nativesessionhandle_options(handle); + } + + /// /// Sets a callback to enable custom setting of platform specific options. /// @@ -397,6 +424,7 @@ class http_client_config #endif std::function m_set_user_nativehandle_options; + std::function m_set_user_nativesessionhandle_options; #if !defined(_WIN32) && !defined(__cplusplus_winrt) std::function m_ssl_context_callback; diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index d163962e8d..0a560d81c0 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -448,6 +448,16 @@ class winhttp_client : public _http_client_communicator } } #endif + + try + { + client_config().invoke_nativesessionhandle_options(m_hSession); + } + catch (...) + { + return report_failure(_XPLATSTR("Error in session handle callback")); + } + // Register asynchronous callback. if(WINHTTP_INVALID_STATUS_CALLBACK == WinHttpSetStatusCallback( m_hSession, From 23c924ac8cd4958f0235c088adc33cccb090c0c7 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Mon, 6 Mar 2017 13:50:34 +0100 Subject: [PATCH 032/438] fix indendation --- Release/include/cpprest/http_client.h | 50 +++++++++++++-------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/Release/include/cpprest/http_client.h b/Release/include/cpprest/http_client.h index 01da04b755..44a8f41350 100644 --- a/Release/include/cpprest/http_client.h +++ b/Release/include/cpprest/http_client.h @@ -312,31 +312,31 @@ class http_client_config } #endif - /// - /// Sets a callback to enable custom setting of platform specific options. - /// - /// - /// The native_handle is the following type depending on the underlying platform: - /// Windows Desktop, WinHTTP - HINTERNET - /// Windows Runtime, WinRT - IXMLHTTPRequest2 * - /// All other platforms, Boost.Asio: - /// https - boost::asio::ssl::stream * - /// http - boost::asio::ip::tcp::socket * - /// - /// A user callback allowing for customization of the session - void set_nativesessionhandle_options(const std::function &callback) - { - m_set_user_nativesessionhandle_options = callback; - } - - /// - /// Invokes a user's callback to allow for customization of the session. - /// - /// A internal implementation handle. - void invoke_nativesessionhandle_options(native_handle handle) const - { - m_set_user_nativesessionhandle_options(handle); - } + /// + /// Sets a callback to enable custom setting of platform specific options. + /// + /// + /// The native_handle is the following type depending on the underlying platform: + /// Windows Desktop, WinHTTP - HINTERNET + /// Windows Runtime, WinRT - IXMLHTTPRequest2 * + /// All other platforms, Boost.Asio: + /// https - boost::asio::ssl::stream * + /// http - boost::asio::ip::tcp::socket * + /// + /// A user callback allowing for customization of the session + void set_nativesessionhandle_options(const std::function &callback) + { + m_set_user_nativesessionhandle_options = callback; + } + + /// + /// Invokes a user's callback to allow for customization of the session. + /// + /// A internal implementation handle. + void invoke_nativesessionhandle_options(native_handle handle) const + { + m_set_user_nativesessionhandle_options(handle); + } /// From a6366cdf400cbd9b80989fddddb0b11529b26ab6 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Sat, 18 Mar 2017 00:00:27 +0100 Subject: [PATCH 033/438] fix a nullptr bug --- Release/include/cpprest/http_client.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Release/include/cpprest/http_client.h b/Release/include/cpprest/http_client.h index 44a8f41350..8be37a178b 100644 --- a/Release/include/cpprest/http_client.h +++ b/Release/include/cpprest/http_client.h @@ -326,7 +326,7 @@ class http_client_config /// A user callback allowing for customization of the session void set_nativesessionhandle_options(const std::function &callback) { - m_set_user_nativesessionhandle_options = callback; + m_set_user_nativesessionhandle_options = callback; } /// @@ -335,7 +335,9 @@ class http_client_config /// A internal implementation handle. void invoke_nativesessionhandle_options(native_handle handle) const { + if (m_set_user_nativesessionhandle_options != nullptr) { m_set_user_nativesessionhandle_options(handle); + } } From 5e5ecaacbd3b3db58080f7b1217c0a9da270b983 Mon Sep 17 00:00:00 2001 From: Christoph Albert Date: Tue, 21 Mar 2017 10:45:49 +0100 Subject: [PATCH 034/438] Fixed race condition in ws_client_wspp.cpp --- .../src/websockets/client/ws_client_wspp.cpp | 61 +++++++++++-------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index ba41dd3134..2d7a15354a 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -114,8 +114,7 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: public: wspp_callback_client(websocket_client_config config) : websocket_client_callback_impl(std::move(config)), - m_state(CREATED), - m_num_sends(0) + m_state(CREATED) #if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) || defined(_WIN32) , m_openssl_failed(false) #endif @@ -415,18 +414,22 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: return pplx::task_from_exception(websocket_exception("Message size too large. Ensure message length is less than UINT_MAX.")); } + bool msg_pending = false; { - if (++m_num_sends == 1) // No sends in progress - { - // Start sending the message - send_msg(msg); - } - else - { - // Only actually have to take the lock if touching the queue. - std::lock_guard lock(m_send_lock); - m_outgoing_msg_queue.push(msg); - } + std::lock_guard lock(m_send_lock); + if (m_outgoing_msg_queue.size() > 0) + { + msg_pending = true; + } + + m_outgoing_msg_queue.push(msg); + } + + // No sends in progress + if (msg_pending == false) + { + // Start sending the message + send_msg(msg); } return pplx::create_task(msg.body_sent()); @@ -562,16 +565,25 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: msg.signal_body_sent(); } - if (--this_client->m_num_sends > 0) + bool msg_pending = false; + websocket_outgoing_message next_msg; { - // Only hold the lock when actually touching the queue. - websocket_outgoing_message next_msg; - { - std::lock_guard lock(this_client->m_send_lock); - next_msg = this_client->m_outgoing_msg_queue.front(); - this_client->m_outgoing_msg_queue.pop(); - } - this_client->send_msg(next_msg); + // Only hold the lock when actually touching the queue. + std::lock_guard lock(this_client->m_send_lock); + + // First message in queue has been sent + this_client->m_outgoing_msg_queue.pop(); + + if (this_client->m_outgoing_msg_queue.size() > 0) + { + next_msg = this_client->m_outgoing_msg_queue.front(); + msg_pending = true; + } + } + + if (msg_pending) + { + this_client->send_msg(next_msg); } }); } @@ -763,12 +775,9 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: // Guards access to m_outgoing_msg_queue std::mutex m_send_lock; - // Queue to order the sends + // Queue to track pending sends std::queue m_outgoing_msg_queue; - // Number of sends in progress and queued up. - std::atomic m_num_sends; - // External callback for handling received and close event std::function m_external_message_handler; std::function m_external_close_handler; From 83e6b2a39f096c1ce86418e4fb4ff870b9fe63b0 Mon Sep 17 00:00:00 2001 From: Chris Deering Date: Tue, 28 Mar 2017 15:47:08 +0100 Subject: [PATCH 035/438] Adding the ability to override the user agent for the oauth2 flow, as well as a scoped server test to verify. --- Release/include/cpprest/oauth2.h | 52 ++++++++++++------- Release/src/http/oauth/oauth2.cpp | 5 ++ .../functional/http/client/oauth2_tests.cpp | 16 ++++++ 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/Release/include/cpprest/oauth2.h b/Release/include/cpprest/oauth2.h index 39b77e643c..7afccdc3e1 100644 --- a/Release/include/cpprest/oauth2.h +++ b/Release/include/cpprest/oauth2.h @@ -204,13 +204,15 @@ class oauth2_config oauth2_config(utility::string_t client_key, utility::string_t client_secret, utility::string_t auth_endpoint, utility::string_t token_endpoint, - utility::string_t redirect_uri, utility::string_t scope=utility::string_t()) : + utility::string_t redirect_uri, utility::string_t scope=utility::string_t(), + utility::string_t user_agent=utility::string_t()) : m_client_key(std::move(client_key)), m_client_secret(std::move(client_secret)), m_auth_endpoint(std::move(auth_endpoint)), m_token_endpoint(std::move(token_endpoint)), m_redirect_uri(std::move(redirect_uri)), m_scope(std::move(scope)), + m_user_agent(std::move(user_agent)), m_implicit_grant(false), m_bearer_auth(true), m_http_basic_auth(true), @@ -436,23 +438,34 @@ class oauth2_config /// void set_access_token_key(utility::string_t access_token_key) { m_access_token_key = std::move(access_token_key); } - /// - /// Get the web proxy object - /// - /// A reference to the web proxy object. - const web_proxy& proxy() const - { - return m_proxy; - } - - /// - /// Set the web proxy object that will be used by token_from_code and token_from_refresh - /// - /// A reference to the web proxy object. - void set_proxy(const web_proxy& proxy) - { - m_proxy = proxy; - } + /// + /// Get the web proxy object + /// + /// A reference to the web proxy object. + const web_proxy& proxy() const + { + return m_proxy; + } + + /// + /// Set the web proxy object that will be used by token_from_code and token_from_refresh + /// + /// A reference to the web proxy object. + void set_proxy(const web_proxy& proxy) + { + m_proxy = proxy; + } + + /// + /// Get user agent to be used in oauth2 flows. + /// + /// User agent string. + const utility::string_t& user_agent() const { return m_user_agent; } + /// + /// Set user agent to be used in oauth2 flows. + /// If none is provided a default user agent is provided. + /// + void set_user_agent(utility::string_t user_agent) { m_user_agent = std::move(user_agent); } private: friend class web::http::client::http_client_config; @@ -489,8 +502,9 @@ class oauth2_config utility::string_t m_redirect_uri; utility::string_t m_scope; utility::string_t m_state; + utility::string_t m_user_agent; - web::web_proxy m_proxy; + web::web_proxy m_proxy; bool m_implicit_grant; bool m_bearer_auth; diff --git a/Release/src/http/oauth/oauth2.cpp b/Release/src/http/oauth/oauth2.cpp index 2ebdd14a26..09a453835c 100644 --- a/Release/src/http/oauth/oauth2.cpp +++ b/Release/src/http/oauth/oauth2.cpp @@ -101,6 +101,11 @@ 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()); + } if (!scope().empty()) { diff --git a/Release/tests/functional/http/client/oauth2_tests.cpp b/Release/tests/functional/http/client/oauth2_tests.cpp index cdc01f94df..d641631ad9 100644 --- a/Release/tests/functional/http/client/oauth2_tests.cpp +++ b/Release/tests/functional/http/client/oauth2_tests.cpp @@ -38,6 +38,16 @@ static bool is_application_x_www_form_urlencoded(test_request *request) return (0 == content_type.find(mime_types::application_x_www_form_urlencoded)); } +static utility::string_t get_request_user_agent(test_request *request) +{ + if (request->m_headers.find(header_names::user_agent) != request->m_headers.end()) + { + return request->m_headers[header_names::user_agent]; + } + + return utility::string_t(); +} + SUITE(oauth2_tests) { @@ -137,6 +147,8 @@ TEST_FIXTURE(oauth2_test_setup, oauth2_token_from_code) { VERIFY_IS_FALSE(m_oauth2_config.is_enabled()); + m_oauth2_config.set_user_agent(U("test_user_agent")); + // Fetch using HTTP Basic authentication. { m_scoped.server()->next_request().then([](test_request *request) @@ -151,6 +163,8 @@ TEST_FIXTURE(oauth2_test_setup, oauth2_token_from_code) U("grant_type=authorization_code&code=789GHI&redirect_uri=https%3A%2F%2Fbar")), request->m_body); + VERIFY_ARE_EQUAL(U("test_user_agent"), get_request_user_agent(request)); + std::map headers; headers[header_names::content_type] = mime_types::application_json; request->reply(status_codes::OK, U(""), headers, "{\"access_token\":\"xyzzy123\",\"token_type\":\"bearer\"}"); @@ -173,6 +187,8 @@ TEST_FIXTURE(oauth2_test_setup, oauth2_token_from_code) U("grant_type=authorization_code&code=789GHI&redirect_uri=https%3A%2F%2Fbar&client_id=123ABC&client_secret=456DEF")), request->m_body); + VERIFY_ARE_EQUAL(U("test_user_agent"), get_request_user_agent(request)); + std::map headers; headers[header_names::content_type] = mime_types::application_json; request->reply(status_codes::OK, U(""), headers, "{\"access_token\":\"xyzzy123\",\"token_type\":\"bearer\"}"); From 8f09ce23290259349e714cfc482f73a8457c0c29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20St=C3=B6ggl?= Date: Thu, 6 Apr 2017 17:05:50 +0200 Subject: [PATCH 036/438] remove spurious executable permissions chmod -x Release/libs/websocketpp/websocketpp/sha1/sha1.hpp chmod -x Release/include/cpprest/oauth1.h chmod -x Release/src/http/oauth/oauth1.cpp --- Release/include/cpprest/oauth1.h | 0 Release/libs/websocketpp/websocketpp/sha1/sha1.hpp | 0 Release/src/http/oauth/oauth1.cpp | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 Release/include/cpprest/oauth1.h mode change 100755 => 100644 Release/libs/websocketpp/websocketpp/sha1/sha1.hpp mode change 100755 => 100644 Release/src/http/oauth/oauth1.cpp diff --git a/Release/include/cpprest/oauth1.h b/Release/include/cpprest/oauth1.h old mode 100755 new mode 100644 diff --git a/Release/libs/websocketpp/websocketpp/sha1/sha1.hpp b/Release/libs/websocketpp/websocketpp/sha1/sha1.hpp old mode 100755 new mode 100644 diff --git a/Release/src/http/oauth/oauth1.cpp b/Release/src/http/oauth/oauth1.cpp old mode 100755 new mode 100644 From 2bd54682b7193f9eeb3e499942bf3fdb14dd57c0 Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Wed, 12 Apr 2017 23:26:00 +0200 Subject: [PATCH 037/438] Handled uncaught exception when request contains misencoded URI. --- .../src/http/listener/http_server_asio.cpp | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 32e4f6cb69..59a7f7e5d5 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -542,30 +542,48 @@ void connection::dispatch_request_to_listener() { // locate the listener: web::http::experimental::listener::details::http_listener_impl* pListener = nullptr; + auto error_status_code = status_codes::NotFound; { - auto path_segments = uri::split_path(uri::decode(m_request.relative_uri().path())); - for (auto i = static_cast(path_segments.size()); i >= 0; --i) + utility::string_t decoded_relative_uri; + bool was_decoding_successful = false; + + try { - std::string path = ""; - for (size_t j = 0; j < static_cast(i); ++j) - { - path += "/" + path_segments[j]; - } - path += "/"; + decoded_relative_uri = uri::decode(m_request.relative_uri().path()); + was_decoding_successful = true; + } + catch (web::uri_exception&) + { + error_status_code = status_codes::BadRequest; + } - pplx::extensibility::scoped_read_lock_t lock(m_p_parent->m_listeners_lock); - auto it = m_p_parent->m_listeners.find(path); - if (it != m_p_parent->m_listeners.end()) + if (was_decoding_successful) + { + auto path_segments = uri::split_path(decoded_relative_uri); + + for (auto i = static_cast(path_segments.size()); i >= 0; --i) { - pListener = it->second; - break; + std::string path = ""; + for (size_t j = 0; j < static_cast(i); ++j) + { + path += "/" + path_segments[j]; + } + path += "/"; + + pplx::extensibility::scoped_read_lock_t lock(m_p_parent->m_listeners_lock); + auto it = m_p_parent->m_listeners.find(path); + if (it != m_p_parent->m_listeners.end()) + { + pListener = it->second; + break; + } } } } if (pListener == nullptr) { - m_request.reply(status_codes::NotFound); + m_request.reply(error_status_code); do_response(false); } else From 089f5a4002a854ef6ceb10274b0316ddf2db07f3 Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Wed, 12 Apr 2017 23:29:06 +0200 Subject: [PATCH 038/438] Added test to check against BadRequest on bad encoded URIs. --- .../listener/request_relative_uri_tests.cpp | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Release/tests/functional/http/listener/request_relative_uri_tests.cpp b/Release/tests/functional/http/listener/request_relative_uri_tests.cpp index 78869f58a3..5ea969b547 100644 --- a/Release/tests/functional/http/listener/request_relative_uri_tests.cpp +++ b/Release/tests/functional/http/listener/request_relative_uri_tests.cpp @@ -115,6 +115,27 @@ TEST(listener_uri_empty_path) listener.close().wait(); } +TEST(listener_invalid_encoded_uri) +{ + uri address(U("http://localhost:45678/")); + http_listener listener(address); + listener.open().wait(); + test_http_client::scoped_client client(address); + test_http_client * p_client = client.client(); + + listener.support([](http_request request) + { + request.reply(status_codes::OK); + }); + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/%invalid/uri"))); + p_client->next_response().then([](test_response *p_response) + { + http_asserts::assert_test_response_equals(p_response, status_codes::BadRequest); + }).wait(); + + listener.close().wait(); +} + } }}}} \ No newline at end of file From 83959175fc3943a7bcd819446344b511519d1163 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 18 Apr 2017 23:57:55 -0700 Subject: [PATCH 039/438] Add PPLX_IMPL option for CPPREST_FORCE_PPLX. --- Release/src/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 44d50407af..f166fc76d6 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -72,6 +72,11 @@ elseif(CPPREST_PPLX_IMPL STREQUAL "win") pplx/threadpool.cpp pplx/pplxwin.cpp ) +elseif(CPPREST_PPLX_IMPL STREQUAL "winpplx") + list(APPEND SOURCES + pplx/threadpool.cpp + pplx/pplxwin.cpp + ) endif() # Http client component @@ -176,6 +181,8 @@ if(CPPREST_PPLX_IMPL STREQUAL "apple") target_link_libraries(cpprest PRIVATE ${COREFOUNDATION} ${SECURITY}) elseif(CPPREST_PPLX_IMPL STREQUAL "linux") elseif(CPPREST_PPLX_IMPL STREQUAL "win") +elseif(CPPREST_PPLX_IMPL STREQUAL "winpplx") + target_compile_definitions(cpprest PUBLIC -DCPPREST_FORCE_PPLX=1) else() message(FATAL_ERROR "Invalid implementation") endif() From 5da5ce11a95f9aa636d38603cd26a24f7ed7ad80 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 19 Apr 2017 00:14:54 -0700 Subject: [PATCH 040/438] Ensure tasks created inside http_client have a try/catch handler to prevent process crashes. --- Release/src/http/client/http_client.cpp | 59 +++++++++++----------- Release/src/http/client/http_client_impl.h | 3 +- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/Release/src/http/client/http_client.cpp b/Release/src/http/client/http_client.cpp index f10de55790..25ded78023 100644 --- a/Release/src/http/client/http_client.cpp +++ b/Release/src/http/client/http_client.cpp @@ -129,20 +129,41 @@ request_context::request_context(const std::shared_ptr<_http_client_communicator responseImpl->_prepare_to_receive_data(); } +void _http_client_communicator::open_and_send_request_async(const std::shared_ptr &request) +{ + auto self = std::static_pointer_cast<_http_client_communicator>(this->shared_from_this()); + // Schedule a task to start sending. + pplx::create_task([self, request] + { + try + { + self->open_and_send_request(request); + } + catch (...) + { + request->report_exception(std::current_exception()); + } + }); +} + void _http_client_communicator::async_send_request(const std::shared_ptr &request) { if (m_client_config.guarantee_order()) { - // Send to call block to be processed. - push_request(request); + pplx::extensibility::scoped_critical_section_t l(m_open_lock); + + if (++m_scheduled == 1) + { + open_and_send_request_async(request); + } + else + { + m_requests_queue.push(request); + } } else { - // Schedule a task to start sending. - pplx::create_task([this, request] - { - open_and_send_request(request); - }); + open_and_send_request_async(request); } } @@ -160,11 +181,7 @@ void _http_client_communicator::finish_request() auto request = m_requests_queue.front(); m_requests_queue.pop(); - // Schedule a task to start sending. - pplx::create_task([this, request] - { - open_and_send_request(request); - }); + open_and_send_request_async(request); } } } @@ -227,24 +244,6 @@ unsigned long _http_client_communicator::open_if_required() return error; } -void _http_client_communicator::push_request(const std::shared_ptr &request) -{ - pplx::extensibility::scoped_critical_section_t l(m_open_lock); - - if (++m_scheduled == 1) - { - // Schedule a task to start sending. - pplx::create_task([this, request]() - { - open_and_send_request(request); - }); - } - else - { - m_requests_queue.push(request); - } -} - inline void request_context::finish() { // If cancellation is enabled and registration was performed, unregister. diff --git a/Release/src/http/client/http_client_impl.h b/Release/src/http/client/http_client_impl.h index e203955591..d14522a35b 100644 --- a/Release/src/http/client/http_client_impl.h +++ b/Release/src/http/client/http_client_impl.h @@ -135,12 +135,11 @@ class _http_client_communicator : public http_pipeline_stage pplx::extensibility::critical_section_t m_open_lock; // Wraps opening the client around sending a request. + void open_and_send_request_async(const std::shared_ptr &request); void open_and_send_request(const std::shared_ptr &request); unsigned long open_if_required(); - void push_request(const std::shared_ptr &request); - // Queue used to guarantee ordering of requests, when applicable. std::queue> m_requests_queue; int m_scheduled; From 5cd9364c4c2107fab5587b4f8a98123332c13cd0 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 19 Apr 2017 00:20:25 -0700 Subject: [PATCH 041/438] CNN permanently moved /US to /us. --- Release/tests/functional/http/client/outside_tests.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Release/tests/functional/http/client/outside_tests.cpp b/Release/tests/functional/http/client/outside_tests.cpp index 662820c027..f10b862ba7 100644 --- a/Release/tests/functional/http/client/outside_tests.cpp +++ b/Release/tests/functional/http/client/outside_tests.cpp @@ -42,12 +42,14 @@ TEST_FIXTURE(uri_address, outside_cnn_dot_com) // CNN's main page doesn't use chunked transfer encoding. http_response response = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + auto code = response.status_code(); + VERIFY_IS_TRUE(code == status_codes::OK || code == status_codes::MovedPermanently); response.content_ready().wait(); // CNN's other pages do use chunked transfer encoding. - response = client.request(methods::GET, U("US")).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + response = client.request(methods::GET, U("us")).get(); + code = response.status_code(); + VERIFY_IS_TRUE(code == status_codes::OK || code == status_codes::MovedPermanently); response.content_ready().wait(); }); } From 5397c9878c01099f2129b67e955b1d7ad7a3f8dc Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 19 Apr 2017 00:44:16 -0700 Subject: [PATCH 042/438] Disable tests that rely on PPL when using CPPREST_FORCE_PPLX. --- Release/tests/functional/pplx/pplx_test/pplx_task_options.cpp | 2 +- Release/tests/functional/streams/stdafx.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Release/tests/functional/pplx/pplx_test/pplx_task_options.cpp b/Release/tests/functional/pplx/pplx_test/pplx_task_options.cpp index b7c4738787..85f9cd4a2c 100644 --- a/Release/tests/functional/pplx/pplx_test/pplx_task_options.cpp +++ b/Release/tests/functional/pplx/pplx_test/pplx_task_options.cpp @@ -11,7 +11,7 @@ #include "stdafx.h" -#if _MSC_VER >= 1800 +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX // Dev12 doesn't have an in-box ambient scheduler, since all tasks execute on ConcRT. // Therefore, we need to provide one. A scheduler that directly executes a functor given to it is // a simple and valid implementation of a PPL scheduler diff --git a/Release/tests/functional/streams/stdafx.h b/Release/tests/functional/streams/stdafx.h index 0d59c580f0..a278f3145e 100644 --- a/Release/tests/functional/streams/stdafx.h +++ b/Release/tests/functional/streams/stdafx.h @@ -19,7 +19,7 @@ #include #include -#if defined(_MSC_VER) && (_MSC_VER >= 1800) +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX #include namespace pplx = Concurrency; #else From f5901c39e843be61e966f24dee9638713c4d149e Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 19 Apr 2017 00:51:54 -0700 Subject: [PATCH 043/438] Handle empty strings in `win32_encryption::decrypt()` --- Release/src/utilities/web_utilities.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Release/src/utilities/web_utilities.cpp b/Release/src/utilities/web_utilities.cpp index f6a951e9c2..367c95c2f4 100644 --- a/Release/src/utilities/web_utilities.cpp +++ b/Release/src/utilities/web_utilities.cpp @@ -115,6 +115,9 @@ win32_encryption::~win32_encryption() plaintext_string win32_encryption::decrypt() const { + if (m_buffer.empty()) + return plaintext_string(new std::wstring()); + // Copy the buffer and decrypt to avoid having to re-encrypt. auto data = plaintext_string(new std::wstring(reinterpret_cast(m_buffer.data()), m_buffer.size() / 2)); if (!CryptUnprotectMemory( From 1402f5d3313bdff533e443fe3526c28f99b46302 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 19 Apr 2017 00:51:54 -0700 Subject: [PATCH 044/438] Not all methods support the Content-Length header. Only send for POST and PUT. --- Release/src/http/client/http_client_asio.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 107a41f82d..80c0fdc597 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -700,9 +700,11 @@ class asio_context : public request_context, public std::enable_shared_from_this ctx->m_needChunked = true; extra_headers.append("Transfer-Encoding:chunked\r\n"); } - else + else if (ctx->m_request.method() == methods::POST || ctx->m_request.method() == methods::PUT) { - // Howver, if there is no body, then just send 0 length. + // Some servers do not accept POST/PUT requests with a content length of 0, such as + // lighttpd - http://serverfault.com/questions/315849/curl-post-411-length-required + // old apache versions - https://issues.apache.org/jira/browse/TS-2902 extra_headers.append("Content-Length: 0\r\n"); } } From 3124c1cae5d5e745ead0ab74c660e64c4b140a5e Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 19 Apr 2017 00:51:54 -0700 Subject: [PATCH 045/438] [http-client] If socket is closed during async_connect, cancel the connection. --- Release/src/http/client/http_client_asio.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 80c0fdc597..f9eb40f73b 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -90,7 +90,8 @@ class asio_connection asio_connection(boost::asio::io_service& io_service) : m_socket(io_service), m_is_reused(false), - m_keep_alive(true) + m_keep_alive(true), + m_closed(false) {} ~asio_connection() @@ -119,6 +120,7 @@ class asio_connection // Ensures closed connections owned by request_context will not be put to pool when they are released. m_keep_alive = false; + m_closed = true; boost::system::error_code error; m_socket.shutdown(tcp::socket::shutdown_both, error); @@ -141,8 +143,14 @@ class asio_connection template void async_connect(const Iterator &begin, const Handler &handler) { - std::lock_guard lock(m_socket_lock); - m_socket.async_connect(begin, handler); + std::unique_lock lock(m_socket_lock); + if (!m_closed) + m_socket.async_connect(begin, handler); + else + { + lock.unlock(); + handler(boost::asio::error::operation_aborted); + } } template @@ -232,6 +240,7 @@ class asio_connection bool m_is_reused; bool m_keep_alive; + bool m_closed; }; /// Implements a connection pool with adaptive connection removal From f566a87d3f45917cc42b18293c3b54a3e53490b3 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 19 Apr 2017 00:51:54 -0700 Subject: [PATCH 046/438] [http-client] Rely on m_timer to call close() when needed --- Release/src/http/client/http_client_asio.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index f9eb40f73b..82b8563cb1 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -485,12 +485,6 @@ class asio_context : public request_context, public std::enable_shared_from_this m_context->m_timer.reset(); auto endpoint = *endpoints; m_context->m_connection->async_connect(endpoint, boost::bind(&ssl_proxy_tunnel::handle_tcp_connect, shared_from_this(), boost::asio::placeholders::error, ++endpoints)); - - // TODO: refactor all interactions with the timeout_timer to avoid racing - if (m_context->m_timer.has_timedout()) - { - m_context->m_connection->close(); - } } } @@ -858,7 +852,6 @@ class asio_context : public request_context, public std::enable_shared_from_this void handle_connect(const boost::system::error_code& ec, tcp::resolver::iterator endpoints) { - m_timer.reset(); if (!ec) { @@ -894,12 +887,6 @@ class asio_context : public request_context, public std::enable_shared_from_this m_timer.reset(); auto endpoint = *endpoints; m_connection->async_connect(endpoint, boost::bind(&asio_context::handle_connect, shared_from_this(), boost::asio::placeholders::error, ++endpoints)); - - // TODO: refactor all interactions with the timeout_timer to avoid racing - if (m_timer.has_timedout()) - { - m_connection->close(); - } } } From 9d9102051e730594107feff379315e10f281f950 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 19 Apr 2017 00:51:54 -0700 Subject: [PATCH 047/438] [threadpool] Disable the asio-backed threadpool when (windows & !websockets) --- Release/src/pplx/threadpool.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Release/src/pplx/threadpool.cpp b/Release/src/pplx/threadpool.cpp index cdffabec57..8d3eadadc6 100644 --- a/Release/src/pplx/threadpool.cpp +++ b/Release/src/pplx/threadpool.cpp @@ -6,6 +6,7 @@ **/ #include "stdafx.h" +#if !defined(CPPREST_EXCLUDE_WEBSOCKETS) || !defined(_WIN32) #include "pplx/threadpool.h" #if !defined(_WIN32) @@ -155,3 +156,4 @@ std::unique_ptr crossplat::threadpool::construct(size_t n { return std::unique_ptr(new threadpool_impl(num_threads)); } +#endif \ No newline at end of file From 115b226fc2862a1157316d68b6bad06c85222539 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 19 Apr 2017 00:51:54 -0700 Subject: [PATCH 048/438] [test-http-server] Unify test server interfaces/impls --- .../http/utilities/include/test_http_server.h | 71 +- .../http/utilities/test_http_server.cpp | 687 ++++++++---------- 2 files changed, 315 insertions(+), 443 deletions(-) diff --git a/Release/tests/functional/http/utilities/include/test_http_server.h b/Release/tests/functional/http/utilities/include/test_http_server.h index f3175e87a0..84eb27d4ab 100644 --- a/Release/tests/functional/http/utilities/include/test_http_server.h +++ b/Release/tests/functional/http/utilities/include/test_http_server.h @@ -32,25 +32,28 @@ class _test_http_server; /// class test_request { + friend class _test_http_server; public: + test_request(unsigned long long reqid, _test_http_server* p_server) : m_request_id(reqid), m_p_server(p_server) {} // APIs to send responses. - TEST_UTILITY_API unsigned long reply(const unsigned short status_code); - TEST_UTILITY_API unsigned long reply(const unsigned short status_code, const utility::string_t &reason_phrase); - TEST_UTILITY_API unsigned long reply( - const unsigned short status_code, - const utility::string_t &reason_phrase, - const std::map &headers); - TEST_UTILITY_API unsigned long reply( + unsigned long reply( const unsigned short status_code, - const utility::string_t &reason_phrase, - const std::map &headers, - const utf8string &data); - TEST_UTILITY_API unsigned long reply( + const utility::string_t &reason_phrase = U(""), + const std::map &headers = std::map(), + const utf8string &data = "") + { + return reply_impl(status_code, reason_phrase, headers, (void *)&data[0], data.size() * sizeof(utf8char)); + } + + unsigned long reply( const unsigned short status_code, const utility::string_t &reason_phrase, const std::map &headers, - const utf16string &data); + const utf16string &data) + { + return reply_impl(status_code, reason_phrase, headers, (void *)&data[0], data.size() * sizeof(utf16char)); + } // API to check if a specific header exists and get it. template @@ -79,14 +82,12 @@ class test_request std::map m_headers; std::vector m_body; private: - friend class _test_http_server; - _test_http_server * m_p_server; - // This is the HTTP Server API Request Id, we don't want to bring in the header file. unsigned long long m_request_id; + _test_http_server * m_p_server; // Helper to send replies. - unsigned long reply_impl( + TEST_UTILITY_API unsigned long reply_impl( const unsigned short status_code, const utility::string_t &reason_phrase, const std::map &headers, @@ -105,37 +106,27 @@ class test_http_server TEST_UTILITY_API test_http_server(const web::http::uri &uri); TEST_UTILITY_API ~test_http_server(); - // APIs to open and close requests. - TEST_UTILITY_API unsigned long open(); - TEST_UTILITY_API unsigned long close(); - // APIs to receive requests. - TEST_UTILITY_API test_request * wait_for_request(); TEST_UTILITY_API pplx::task next_request(); - TEST_UTILITY_API std::vector wait_for_requests(const size_t count); TEST_UTILITY_API std::vector> next_requests(const size_t count); + // Enable early close + TEST_UTILITY_API void close(); + // RAII pattern for test_http_server. - class scoped_server - { - public: - scoped_server(const web::http::uri &uri) - { - m_p_server = new test_http_server(uri); - VERIFY_ARE_EQUAL(0u, m_p_server->open()); - } - ~scoped_server() - { - VERIFY_ARE_EQUAL(0u, m_p_server->close()); - delete m_p_server; - } - test_http_server *server() { return m_p_server; } - private: - test_http_server * m_p_server; - }; + class scoped_server; + +private: + std::unique_ptr<_test_http_server> m_p_impl; +}; +class test_http_server::scoped_server +{ +public: + scoped_server(const web::http::uri &uri) : m_p_server(uri) {} + test_http_server *server() { return &m_p_server; } private: - _test_http_server *m_p_impl; + test_http_server m_p_server; }; }}}} diff --git a/Release/tests/functional/http/utilities/test_http_server.cpp b/Release/tests/functional/http/utilities/test_http_server.cpp index 3e6767f239..cd359b1592 100644 --- a/Release/tests/functional/http/utilities/test_http_server.cpp +++ b/Release/tests/functional/http/utilities/test_http_server.cpp @@ -17,14 +17,17 @@ #pragma warning ( disable : 4457 ) #include #pragma warning ( pop ) +#else +#include "cpprest/http_listener.h" #endif #include #include "cpprest/uri.h" #include "test_http_server.h" -#include "cpprest/http_listener.h" #include +#include +#include using namespace web; using namespace utility; @@ -32,6 +35,46 @@ using namespace utility::conversions; namespace tests { namespace functional { namespace http { namespace utilities { + +struct test_server_queue +{ + std::mutex m_lock; + std::deque> m_requests; + std::vector> m_requests_memory; + + void close() + { + std::lock_guard lk(m_lock); + for (auto&& tce : m_requests) + tce.set_exception(std::runtime_error("test_http_server closed.")); + } + + ~test_server_queue() + { + close(); + } + + void on_request(std::unique_ptr req) + { + std::lock_guard lk(m_lock); + VERIFY_IS_FALSE(m_requests.empty(), "There are no pending calls to next_request."); + if (m_requests.empty()) + return; + auto tce = std::move(m_requests.front()); + m_requests.pop_front(); + m_requests_memory.push_back(std::move(req)); + tce.set(m_requests_memory.back().get()); + } + + pplx::task next_request() + { + pplx::task_completion_event tce; + std::lock_guard lock(m_lock); + m_requests.push_back(tce); + return pplx::create_task(tce); + } +}; + #if defined(_WIN32) // Helper function to parse verb from Windows HTTP Server API. static utility::string_t parse_verb(const HTTP_REQUEST *p_http_request) @@ -179,57 +222,47 @@ class _test_http_server { inline bool is_error_code(ULONG error_code) { - return error_code == ERROR_OPERATION_ABORTED || error_code == ERROR_CONNECTION_INVALID || error_code == ERROR_NETNAME_DELETED - || m_isClosing; + return error_code == ERROR_OPERATION_ABORTED || error_code == ERROR_CONNECTION_INVALID || error_code == ERROR_NETNAME_DELETED || m_closing == 1; } public: - _test_http_server(const utility::string_t &uri) - : m_uri(uri), m_session(0), m_url_group(0), m_request_queue(nullptr), m_isClosing(false) - { - HTTPAPI_VERSION httpApiVersion = HTTPAPI_VERSION_2; - HttpInitialize(httpApiVersion, HTTP_INITIALIZE_SERVER, NULL); - } - ~_test_http_server() - { - HttpTerminate(HTTP_INITIALIZE_SERVER, NULL); - } - - unsigned long open() + _test_http_server(const web::uri &uri) + : m_uri(uri), m_session(0), m_url_group(0), m_request_queue(nullptr) { // Open server session. HTTPAPI_VERSION httpApiVersion = HTTPAPI_VERSION_2; + HttpInitialize(httpApiVersion, HTTP_INITIALIZE_SERVER, NULL); ULONG error_code = HttpCreateServerSession(httpApiVersion, &m_session, 0); - if(error_code) + if (error_code) { - return error_code; + throw std::runtime_error("error code: " + std::to_string(error_code)); } // Create Url group. error_code = HttpCreateUrlGroup(m_session, &m_url_group, 0); - if(error_code) + if (error_code) { - return error_code; + throw std::runtime_error("error code: " + std::to_string(error_code)); } // Create request queue. error_code = HttpCreateRequestQueue(httpApiVersion, U("test_http_server"), NULL, NULL, &m_request_queue); - if(error_code) + if (error_code) { - return error_code; + throw std::runtime_error("error code: " + std::to_string(error_code)); } // Windows HTTP Server API will not accept a uri with an empty path, it must have a '/'. - auto host_uri = m_uri.to_string(); - if(m_uri.is_path_empty() && host_uri[host_uri.length() - 1] != '/' && m_uri.query().empty() && m_uri.fragment().empty()) + auto host_uri = uri.to_string(); + if (uri.is_path_empty() && host_uri[host_uri.length() - 1] != '/' && uri.query().empty() && uri.fragment().empty()) { host_uri.append(U("/")); } // Add Url. error_code = HttpAddUrlToUrlGroup(m_url_group, host_uri.c_str(), (HTTP_URL_CONTEXT)this, 0); - if(error_code) + if (error_code) { - return error_code; + throw std::runtime_error("error code: " + std::to_string(error_code)); } // Associate Url group with request queue. @@ -237,141 +270,124 @@ class _test_http_server bindingInfo.RequestQueueHandle = m_request_queue; bindingInfo.Flags.Present = 1; error_code = HttpSetUrlGroupProperty(m_url_group, HttpServerBindingProperty, &bindingInfo, sizeof(HTTP_BINDING_INFO)); - if(error_code) + if (error_code) { - return error_code; + throw std::runtime_error("error code: " + std::to_string(error_code)); } - - // Spawn a task to handle receiving incoming requests. - m_request_task = pplx::create_task([this]() - { - ConcRTOversubscribe osubs; // Oversubscription for long running ConcRT tasks - for(;;) - { - const ULONG buffer_length = 1024 * 4; - char buffer[buffer_length]; - ULONG bytes_received = 0; - HTTP_REQUEST *p_http_request = (HTTP_REQUEST *)buffer; - // Read in everything except the body. - ULONG error_code2 = HttpReceiveHttpRequest( - m_request_queue, - HTTP_NULL_ID, - 0, - p_http_request, - buffer_length, - &bytes_received, - 0); - if (is_error_code(error_code2)) + // Launch listener thread + m_thread = std::thread([](_test_http_server* self) { + for (;;) + { + auto req = self->sync_get_request(); + if (req == nullptr) break; - else - VERIFY_ARE_EQUAL(0, error_code2); - - // Now create request structure. - auto p_test_request = new test_request(); - m_requests_memory.push_back(p_test_request); - p_test_request->m_request_id = p_http_request->RequestId; - p_test_request->m_p_server = this; - p_test_request->m_path = utf8_to_utf16(p_http_request->pRawUrl); - p_test_request->m_method = parse_verb(p_http_request); - p_test_request->m_headers = parse_http_headers(p_http_request->Headers); - - // Read in request body. - ULONG content_length; - const bool has_content_length = p_test_request->match_header(U("Content-Length"), content_length); - if(has_content_length && content_length > 0) - { - p_test_request->m_body.resize(content_length); - auto result = - HttpReceiveRequestEntityBody( - m_request_queue, - p_http_request->RequestId, - HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER, - &p_test_request->m_body[0], - content_length, - &bytes_received, - NULL); - if (is_error_code(result)) - break; - else - VERIFY_ARE_EQUAL(0, result); - } - - utility::string_t transfer_encoding; - const bool has_transfer_encoding = p_test_request->match_header(U("Transfer-Encoding"), transfer_encoding); - if(has_transfer_encoding && transfer_encoding == U("chunked")) - { - content_length = 0; - char buf[4096]; - auto result = - HttpReceiveRequestEntityBody( - m_request_queue, - p_http_request->RequestId, - HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER, - (LPVOID)buf, - 4096, - &bytes_received, - NULL); - - while ( result == NO_ERROR ) - { - content_length += bytes_received; - p_test_request->m_body.resize(content_length); - memcpy(&p_test_request->m_body[content_length-bytes_received], buf, bytes_received); - - result = - HttpReceiveRequestEntityBody( - m_request_queue, - p_http_request->RequestId, - HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER, - (LPVOID)buf, - 4096, - &bytes_received, - NULL); - } - - if (is_error_code(result)) - break; - else - VERIFY_ARE_EQUAL(ERROR_HANDLE_EOF, result); - } - - // Place request buffer. - Concurrency::asend(m_requests, p_test_request); + + self->m_queue.on_request(std::move(req)); } - }); - - return 0; + }, this); } - unsigned long close() + ~_test_http_server() { + close(); + + m_thread.join(); + + HttpTerminate(HTTP_INITIALIZE_SERVER, NULL); + } + + std::unique_ptr sync_get_request() { - // Wait for all outstanding next_requests to be processed. A hang here means the test case - // isn't making sure all the requests have been satisfied. We will only wait for 1 minute and then - // allow the test case to continue anyway. This should be enough time for any outstanding requests to come - // in and avoid causing an AV. - // - // If the requests haven't been fullfilled by now then there is a test bug so we still will mark failure. - bool allRequestsSatisfied = true; - std::for_each(m_all_next_request_tasks.begin(), m_all_next_request_tasks.end(), [&](pplx::task request_task) + ConcRTOversubscribe osubs; // Oversubscription for long running ConcRT tasks + const ULONG buffer_length = 1024 * 4; + char buffer[buffer_length]; + ULONG bytes_received = 0; + HTTP_REQUEST *p_http_request = (HTTP_REQUEST *)buffer; + + // Read in everything except the body. + ULONG error_code2 = HttpReceiveHttpRequest( + m_request_queue, + HTTP_NULL_ID, + 0, + p_http_request, + buffer_length, + &bytes_received, + 0); + if (error_code2 != 0) { - if(!request_task.is_done()) + return nullptr; + } + + // Now create request structure. + auto p_test_request = std::unique_ptr(new test_request(p_http_request->RequestId, this)); + p_test_request->m_path = utf8_to_utf16(p_http_request->pRawUrl); + p_test_request->m_method = parse_verb(p_http_request); + p_test_request->m_headers = parse_http_headers(p_http_request->Headers); + + // Read in request body. + ULONG content_length; + const bool has_content_length = p_test_request->match_header(U("Content-Length"), content_length); + if(has_content_length && content_length > 0) + { + p_test_request->m_body.resize(content_length); + auto result = + HttpReceiveRequestEntityBody( + m_request_queue, + p_http_request->RequestId, + HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER, + &p_test_request->m_body[0], + content_length, + &bytes_received, + NULL); + if (result != 0) + return nullptr; + } + + utility::string_t transfer_encoding; + const bool has_transfer_encoding = p_test_request->match_header(U("Transfer-Encoding"), transfer_encoding); + if (has_transfer_encoding && transfer_encoding == U("chunked")) + { + content_length = 0; + char buf[4096]; + auto result = + HttpReceiveRequestEntityBody( + m_request_queue, + p_http_request->RequestId, + HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER, + (LPVOID)buf, + 4096, + &bytes_received, + NULL); + + while (result == NO_ERROR) { - allRequestsSatisfied = false; + content_length += bytes_received; + p_test_request->m_body.resize(content_length); + memcpy(&p_test_request->m_body[content_length - bytes_received], buf, bytes_received); + + result = + HttpReceiveRequestEntityBody( + m_request_queue, + p_http_request->RequestId, + HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER, + (LPVOID)buf, + 4096, + &bytes_received, + NULL); } - }); - if(!allRequestsSatisfied) - { - // Just wait for either all the requests to finish or for the timer task, it doesn't matter which one. - auto allRequestsTask = pplx::when_all(m_all_next_request_tasks.begin(), m_all_next_request_tasks.end()).then([](const std::vector &){}); - auto timerTask = pplx::create_task([]() { ::tests::common::utilities::os_utilities::sleep(30000); }); - (timerTask || allRequestsTask).wait(); - VERIFY_IS_TRUE(false, "HTTP test case didn't properly wait for all requests to be satisfied."); + if (is_error_code(result)) + return nullptr; + else + VERIFY_ARE_EQUAL(ERROR_HANDLE_EOF, result); } - // Signal shutting down - m_isClosing = true; + return p_test_request; + } + + unsigned long close() + { + m_closing = 1; // Windows HTTP Server API will not accept a uri with an empty path, it must have a '/'. utility::string_t host_uri = m_uri.to_string(); @@ -389,144 +405,163 @@ class _test_http_server // Stop request queue. error_code = HttpShutdownRequestQueue(m_request_queue); - m_request_task.wait(); if(error_code) { return error_code; } - // Release memory for each request. - std::for_each(m_requests_memory.begin(), m_requests_memory.end(), [](test_request *p_request) - { - delete p_request; - }); - // Close all resources. HttpCloseRequestQueue(m_request_queue); HttpCloseUrlGroup(m_url_group); HttpCloseServerSession(m_session); - return 0; - } - - test_request * wait_for_request() - { - return wait_for_requests(1)[0]; - } + m_queue.close(); - pplx::task next_request() - { - auto next_request_task = pplx::create_task([this]() -> test_request * - { - return wait_for_request(); - }); - m_all_next_request_tasks.push_back(next_request_task); - return next_request_task; + return 0; } - std::vector> next_requests(const size_t count) + unsigned long send_reply( + const unsigned long long request_id, + const unsigned short status_code, + const utility::string_t &reason_phrase, + const std::map &headers, + void * data, + size_t data_length) { - std::vector> events; - std::vector> requests; - for(size_t i = 0; i < count; ++i) - { - events.push_back(pplx::task_completion_event()); - auto next_request_task = pplx::create_task(events[i]); - requests.push_back(next_request_task); - m_all_next_request_tasks.push_back(next_request_task); - } - pplx::create_task([this, count, events]() + ConcRTOversubscribe osubs; // Oversubscription for long running ConcRT tasks + HTTP_RESPONSE response; + ZeroMemory(&response, sizeof(HTTP_RESPONSE)); + response.StatusCode = status_code; + std::string reason(reason_phrase.begin(), reason_phrase.end()); + response.pReason = reason.c_str(); + response.ReasonLength = (USHORT)reason.length(); + + // Add headers. + std::vector headers_buffer; + response.Headers.UnknownHeaderCount = (USHORT)headers.size() + 1; + response.Headers.pUnknownHeaders = new HTTP_UNKNOWN_HEADER[headers.size() + 1]; + headers_buffer.resize(headers.size() * 2 + 2); + + // Add the no cache header. + headers_buffer[0] = "Cache-Control"; + headers_buffer[1] = "no-cache"; + response.Headers.pUnknownHeaders[0].NameLength = (USHORT)headers_buffer[0].size(); + response.Headers.pUnknownHeaders[0].pName = headers_buffer[0].c_str(); + response.Headers.pUnknownHeaders[0].RawValueLength = (USHORT)headers_buffer[1].size(); + response.Headers.pUnknownHeaders[0].pRawValue = headers_buffer[1].c_str(); + + // Add all other headers. + if (!headers.empty()) { - for(size_t i = 0; i < count; ++i) + int headerIndex = 1; + for (auto iter = headers.begin(); iter != headers.end(); ++iter, ++headerIndex) { - events[i].set(wait_for_request()); + headers_buffer[headerIndex * 2] = utf16_to_utf8(iter->first); + headers_buffer[headerIndex * 2 + 1] = utf16_to_utf8(iter->second); + + // TFS 624150 +#pragma warning (push) +#pragma warning (disable : 6386) + response.Headers.pUnknownHeaders[headerIndex].NameLength = (USHORT)headers_buffer[headerIndex * 2].size(); +#pragma warning (pop) + + response.Headers.pUnknownHeaders[headerIndex].pName = headers_buffer[headerIndex * 2].c_str(); + response.Headers.pUnknownHeaders[headerIndex].RawValueLength = (USHORT)headers_buffer[headerIndex * 2 + 1].size(); + response.Headers.pUnknownHeaders[headerIndex].pRawValue = headers_buffer[headerIndex * 2 + 1].c_str(); } - }); - return requests; - } + } - std::vector wait_for_requests(const size_t count) - { - std::vector m_test_requests; - for(size_t i = 0; i < count; ++i) + // Add body. + response.EntityChunkCount = 0; + HTTP_DATA_CHUNK dataChunk; + if (data_length != 0) { - m_test_requests.push_back(Concurrency::receive(m_requests)); + response.EntityChunkCount = 1; + dataChunk.DataChunkType = HttpDataChunkFromMemory; + dataChunk.FromMemory.pBuffer = (void *)data; + dataChunk.FromMemory.BufferLength = (ULONG)data_length; + response.pEntityChunks = &dataChunk; } - return m_test_requests; - } -private: - friend class test_request; + // Synchronously sending the request. + unsigned long error_code = HttpSendHttpResponse( + m_request_queue, + request_id, + HTTP_SEND_RESPONSE_FLAG_DISCONNECT, + &response, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); + + // Free memory needed for headers. + if (response.Headers.UnknownHeaderCount != 0) + { + delete[] response.Headers.pUnknownHeaders; + } - ::http::uri m_uri; - pplx::task m_request_task; - Concurrency::unbounded_buffer m_requests; + return error_code; + } - // Used to store all requests to simplify memory management. - std::vector m_requests_memory; +public: + test_server_queue m_queue; - // Used to store all tasks created to wait on requests to catch any test cases - // which fail to make sure any next_request tasks have completed before exiting. - // Test cases rarely use more than a couple so it is ok to store them all. - std::vector> m_all_next_request_tasks; +private: + std::atomic m_closing = 0; + web::uri m_uri; HTTP_SERVER_SESSION_ID m_session; HTTP_URL_GROUP_ID m_url_group; HANDLE m_request_queue; - std::atomic m_isClosing; + + std::thread m_thread; }; #else class _test_http_server { +public: + test_server_queue m_queue; + private: - const utility::string_t m_uri; - typename web::http::experimental::listener::http_listener m_listener; - pplx::extensibility::critical_section_t m_lock; - std::vector> m_requests; + web::http::experimental::listener::http_listener m_listener; + std::atomic m_last_request_id; + std::mutex m_response_lock; std::unordered_map m_responding_requests; - volatile std::atomic m_cancel; - public: - _test_http_server(const utility::string_t& uri) - : m_uri(uri) - , m_listener(uri) + _test_http_server(const web::uri& uri) + : m_listener(uri) , m_last_request_id(0) - , m_cancel(0) { - m_listener.support([&](web::http::http_request result) -> void + auto handler = [this](web::http::http_request result) -> void { - auto tr = new test_request(); + auto tr = std::unique_ptr(new test_request(this->m_last_request_id++, this)); tr->m_method = result.method(); tr->m_path = result.request_uri().resource().to_string(); if (tr->m_path.empty()) tr->m_path = U("/"); - tr->m_p_server = this; - tr->m_request_id = ++m_last_request_id; for (auto it = result.headers().begin(); it != result.headers().end(); ++it) tr->m_headers[it->first] = it->second; - + tr->m_body = result.extract_vector().get(); { - pplx::extensibility::scoped_critical_section_t lock(m_lock); + std::lock_guard lock(m_response_lock); m_responding_requests[tr->m_request_id] = result; } - while (!m_cancel) - { - pplx::extensibility::scoped_critical_section_t lock(m_lock); - if (m_requests.size() > 0) - { - m_requests[0].set(tr); - m_requests.erase(m_requests.begin()); - return; - } - } - }); + m_queue.on_request(std::move(tr)); + }; + m_listener.support(handler); + m_listener.support(web::http::methods::OPTIONS, handler); + m_listener.support(web::http::methods::TRCE, handler); + + m_listener.open().wait(); } ~_test_http_server() @@ -534,17 +569,10 @@ class _test_http_server close(); } - unsigned long open() { m_listener.open().wait(); return 0;} - unsigned long close() + void close() { - ++m_cancel; m_listener.close().wait(); - return 0; - } - - test_request * wait_for_request() - { - return next_request().get(); + m_queue.close(); } unsigned long send_reply( @@ -557,7 +585,7 @@ class _test_http_server { web::http::http_request request; { - pplx::extensibility::scoped_critical_section_t lock(m_lock); + std::lock_guard lock(m_response_lock); auto it = m_responding_requests.find(request_id); if (it == m_responding_requests.end()) throw std::runtime_error("no such request awaiting response"); @@ -576,163 +604,13 @@ class _test_http_server std::vector body_data(data_bytes, data_bytes + data_length); response.set_body(std::move(body_data)); - request.reply(response); + request.reply(response).get(); return 0; } - - pplx::extensibility::critical_section_t m_next_request_lock; - pplx::task next_request() - { - pplx::task_completion_event tce; - pplx::extensibility::scoped_critical_section_t lock(m_lock); - m_requests.push_back(tce); - return pplx::create_task(tce); - } - - std::vector> next_requests(const size_t count) - { - std::vector> result; - for (size_t i = 0; i < count; ++i) - { - result.push_back(next_request()); - } - return result; - } - - std::vector wait_for_requests(const size_t count) - { - std::vector requests; - for (size_t i = 0; i < count; ++i) - { - requests.push_back(wait_for_request()); - } - return requests; - } }; #endif -unsigned long test_request::reply(const unsigned short status_code) -{ - return reply(status_code, U("")); -} - -unsigned long test_request::reply(const unsigned short status_code, const utility::string_t &reason_phrase) -{ - return reply(status_code, reason_phrase, std::map(), ""); -} - -unsigned long test_request::reply( - const unsigned short status_code, - const utility::string_t &reason_phrase, - const std::map &headers) -{ - return reply(status_code, reason_phrase, headers, U("")); -} - -unsigned long test_request::reply( - const unsigned short status_code, - const utility::string_t &reason_phrase, - const std::map &headers, - const utf8string &data) -{ - return reply_impl(status_code, reason_phrase, headers, (void *)&data[0], data.size() * sizeof(utf8char)); -} - -unsigned long test_request::reply( - const unsigned short status_code, - const utility::string_t &reason_phrase, - const std::map &headers, - const utf16string &data) -{ - return reply_impl(status_code, reason_phrase, headers, (void *)&data[0], data.size() * sizeof(utf16char)); -} - -#if defined(_WIN32) -unsigned long test_request::reply_impl( - const unsigned short status_code, - const utility::string_t &reason_phrase, - const std::map &headers, - void * data, - size_t data_length) -{ - ConcRTOversubscribe osubs; // Oversubscription for long running ConcRT tasks - HTTP_RESPONSE response; - ZeroMemory(&response, sizeof(HTTP_RESPONSE)); - response.StatusCode = status_code; - std::string reason(reason_phrase.begin(), reason_phrase.end()); - response.pReason = reason.c_str(); - response.ReasonLength = (USHORT)reason.length(); - - // Add headers. - std::vector headers_buffer; - response.Headers.UnknownHeaderCount = (USHORT)headers.size() + 1; - response.Headers.pUnknownHeaders = new HTTP_UNKNOWN_HEADER[headers.size() + 1]; - headers_buffer.resize(headers.size() * 2 + 2); - - // Add the no cache header. - headers_buffer[0] = "Cache-Control"; - headers_buffer[1] = "no-cache"; - response.Headers.pUnknownHeaders[0].NameLength = (USHORT)headers_buffer[0].size(); - response.Headers.pUnknownHeaders[0].pName = headers_buffer[0].c_str(); - response.Headers.pUnknownHeaders[0].RawValueLength = (USHORT)headers_buffer[1].size(); - response.Headers.pUnknownHeaders[0].pRawValue = headers_buffer[1].c_str(); - - // Add all other headers. - if(!headers.empty()) - { - int headerIndex = 1; - for(auto iter = headers.begin(); iter != headers.end(); ++iter, ++headerIndex) - { - headers_buffer[headerIndex * 2] = utf16_to_utf8(iter->first); - headers_buffer[headerIndex * 2 + 1] = utf16_to_utf8(iter->second); - -// TFS 624150 -#pragma warning (push) -#pragma warning (disable : 6386) - response.Headers.pUnknownHeaders[headerIndex].NameLength = (USHORT)headers_buffer[headerIndex * 2].size(); -#pragma warning (pop) - - response.Headers.pUnknownHeaders[headerIndex].pName = headers_buffer[headerIndex * 2].c_str(); - response.Headers.pUnknownHeaders[headerIndex].RawValueLength = (USHORT)headers_buffer[headerIndex * 2 + 1].size(); - response.Headers.pUnknownHeaders[headerIndex].pRawValue = headers_buffer[headerIndex * 2 + 1].c_str(); - } - } - - // Add body. - response.EntityChunkCount = 0; - HTTP_DATA_CHUNK dataChunk; - if(data_length != 0) - { - response.EntityChunkCount = 1; - dataChunk.DataChunkType = HttpDataChunkFromMemory; - dataChunk.FromMemory.pBuffer = (void *)data; - dataChunk.FromMemory.BufferLength = (ULONG)data_length; - response.pEntityChunks = &dataChunk; - } - - // Synchronously sending the request. - unsigned long error_code = HttpSendHttpResponse( - m_p_server->m_request_queue, - m_request_id, - HTTP_SEND_RESPONSE_FLAG_DISCONNECT, - &response, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - - // Free memory needed for headers. - if(response.Headers.UnknownHeaderCount != 0) - { - delete [] response.Headers.pUnknownHeaders; - } - - return error_code; -} -#else unsigned long test_request::reply_impl( const unsigned short status_code, const utility::string_t &reason_phrase, @@ -742,22 +620,25 @@ unsigned long test_request::reply_impl( { return m_p_server->send_reply(m_request_id, status_code, reason_phrase, headers, data, data_length); } -#endif - -test_http_server::test_http_server(const web::http::uri &uri) { m_p_impl = new _test_http_server(uri.to_string()); } -test_http_server::~test_http_server() { delete m_p_impl; } - -unsigned long test_http_server::open() { return m_p_impl->open(); } - -unsigned long test_http_server::close() { return m_p_impl->close(); } +test_http_server::test_http_server(const web::http::uri &uri) +{ + m_p_impl = std::unique_ptr<_test_http_server>(new _test_http_server(uri)); +} -test_request * test_http_server::wait_for_request() { return m_p_impl->wait_for_request(); } +test_http_server::~test_http_server() { } -pplx::task test_http_server::next_request() { return m_p_impl->next_request(); } +pplx::task test_http_server::next_request() { return m_p_impl->m_queue.next_request(); } -std::vector test_http_server::wait_for_requests(const size_t count) { return m_p_impl->wait_for_requests(count); } +std::vector> test_http_server::next_requests(const size_t count) +{ + std::vector> ret; + ret.reserve(count); + for (size_t x = 0; x < count; ++x) + ret.push_back(next_request()); + return ret; +} -std::vector> test_http_server::next_requests(const size_t count) { return m_p_impl->next_requests(count); } +void test_http_server::close() { m_p_impl->close(); } }}}} From 0d1d5d16ee09183d5df702ae5adf129c79a8dc70 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 19 Apr 2017 00:51:54 -0700 Subject: [PATCH 049/438] Improve test robustness across the board. Themes are: - Always wait on tasks so testing can continue on failure - Add aggressive timeouts to drastically reduce time taken by failing tests - Reduce races --- .../tests/common/UnitTestpp/src/CheckMacros.h | 15 + .../http/client/authentication_tests.cpp | 333 +++++++++--------- .../http/client/building_request_tests.cpp | 52 +-- .../http/client/connections_and_errors.cpp | 124 ++++--- .../http/client/multiple_requests.cpp | 20 +- .../functional/http/client/outside_tests.cpp | 5 +- .../http/client/progress_handler_tests.cpp | 30 +- .../http/listener/connections_and_errors.cpp | 3 + 8 files changed, 329 insertions(+), 253 deletions(-) diff --git a/Release/tests/common/UnitTestpp/src/CheckMacros.h b/Release/tests/common/UnitTestpp/src/CheckMacros.h index 92ccca0c31..8831d7a1af 100644 --- a/Release/tests/common/UnitTestpp/src/CheckMacros.h +++ b/Release/tests/common/UnitTestpp/src/CheckMacros.h @@ -107,6 +107,7 @@ #define VERIFY_ARE_EQUAL(expected, actual, ...) CHECK_EQUAL(expected, actual, ##__VA_ARGS__) #endif +#define VERIFY_NO_THROWS(expression) CHECK_NO_THROW(expression) #define VERIFY_THROWS(expression, exception) CHECK_THROW(expression, exception) #define VERIFY_IS_NOT_NULL(expression) CHECK_NOT_NULL(expression) #define VERIFY_IS_NULL(expression) CHECK_NULL(expression) @@ -215,6 +216,20 @@ UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), "Expected exception: \"" #ExpectedExceptionType "\" not thrown"); \ UNITTEST_MULTILINE_MACRO_END +#define CHECK_NO_THROW(expression) \ + UNITTEST_MULTILINE_MACRO_BEGIN \ + try { \ + expression; \ + } catch(const std::exception & _exc) { \ + std::string _msg("(" #expression ") threw exception: "); \ + _msg.append(_exc.what()); \ + UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), _msg.c_str()); \ + } catch (...) { \ + std::string _msg("(" #expression ") threw exception: <...>"); \ + UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), _msg.c_str()); \ + } \ + UNITTEST_MULTILINE_MACRO_END + #define CHECK_ASSERT(expression) \ UNITTEST_MULTILINE_MACRO_BEGIN \ UnitTest::Detail::ExpectAssert(true); \ diff --git a/Release/tests/functional/http/client/authentication_tests.cpp b/Release/tests/functional/http/client/authentication_tests.cpp index b27658ef9d..9caa86b0b6 100644 --- a/Release/tests/functional/http/client/authentication_tests.cpp +++ b/Release/tests/functional/http/client/authentication_tests.cpp @@ -52,81 +52,86 @@ SUITE(authentication_tests) TEST_FIXTURE(uri_address, auth_no_data, "Ignore:Linux", "89", "Ignore:Apple", "89") { - test_http_server::scoped_server scoped(m_uri); - http_client_config client_config; - web::credentials cred(U("some_user"), U("some_password")); // WinHTTP requires non-empty password - client_config.set_credentials(cred); - http_client client(m_uri, client_config); - const method mtd = methods::POST; + pplx::task t, t2; + { + test_http_server::scoped_server scoped(m_uri); + http_client_config client_config; + web::credentials cred(U("some_user"), U("some_password")); // WinHTTP requires non-empty password + client_config.set_credentials(cred); + http_client client(m_uri, client_config); + const method mtd = methods::POST; - http_request msg(mtd); + http_request msg(mtd); - auto replyFunc = [&](test_request *p_request) + t = scoped.server()->next_request().then([&](test_request *p_request) { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); - p_request->reply(200); - }; + http_asserts::assert_test_request_equals(p_request, mtd, U("/")); - scoped.server()->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, mtd, U("/")); + // Auth header + std::map headers; + headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); - // Auth header - std::map headers; - headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); + // unauthorized + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); - // unauthorized - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); - - }).then([&scoped, replyFunc]() - { - // Client resent the request - scoped.server()->next_request().then(replyFunc); - }); + }); + t2 = scoped.server()->next_request().then([&](test_request *p_request) + { + http_asserts::assert_test_request_equals(p_request, methods::POST, U("/")); + p_request->reply(200); + }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + } + try { t.get(); } + catch (...) { VERIFY_ARE_EQUAL(0, 1); } + try { t2.get(); } + catch (...) { VERIFY_ARE_EQUAL(0, 1); } } // TFS 648783 #ifndef __cplusplus_winrt TEST_FIXTURE(uri_address, proxy_auth_known_contentlength, "Ignore:Linux", "88", "Ignore:Apple", "88") { - test_http_server::scoped_server scoped(m_uri); - http_client_config client_config; - web::credentials cred(U("some_user"), U("some_password")); // WinHTTP requires non-empty password - client_config.set_credentials(cred); - http_client client(m_uri, client_config); - const method mtd = methods::POST; - utility::string_t contents(U("Hello World")); - - http_request msg(mtd); - msg.set_body(contents); - - auto replyFunc = [&](test_request *p_request) + pplx::task t, t2; + { + test_http_server::scoped_server scoped(m_uri); + http_client_config client_config; + web::credentials cred(U("some_user"), U("some_password")); // WinHTTP requires non-empty password + client_config.set_credentials(cred); + http_client client(m_uri, client_config); + const method mtd = methods::POST; + utility::string_t contents(U("Hello World")); + + http_request msg(mtd); + msg.set_body(contents); + + t = scoped.server()->next_request().then([&](test_request *p_request) { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("text/plain; charset=utf-8"), contents); + http_asserts::assert_test_request_equals(p_request, mtd, U("/")); - p_request->reply(200); - }; + // Auth header + std::map headers; + headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); - scoped.server()->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, mtd, U("/")); + // unauthorized + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); - // Auth header - std::map headers; - headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); + }); - // unauthorized - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); + t2 = scoped.server()->next_request().then([&](test_request *p_request) + { + http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("text/plain; charset=utf-8"), contents); - }).then([&scoped, replyFunc]() - { - // Client resent the request - scoped.server()->next_request().then(replyFunc); - }); + p_request->reply(200); + }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + } + try { t.get(); } + catch (...) { VERIFY_ARE_EQUAL(0, 1); } + try { t2.get(); } + catch (...) { VERIFY_ARE_EQUAL(0, 1); } } #endif @@ -164,20 +169,22 @@ TEST_FIXTURE(uri_address, proxy_auth_noseek, "Ignore:Linux", "88", "Ignore:Apple #ifndef __cplusplus_winrt TEST_FIXTURE(uri_address, proxy_auth_unknown_contentlength, "Ignore:Linux", "88", "Ignore:Apple", "88") { - test_http_server::scoped_server scoped(m_uri); - http_client_config client_config; - web::credentials cred(U("some_user"), U("some_password")); // WinHTTP requires non-empty password - client_config.set_credentials(cred); - http_client client(m_uri, client_config); - const method mtd = methods::POST; + pplx::task t; + { + test_http_server::scoped_server scoped(m_uri); + http_client_config client_config; + web::credentials cred(U("some_user"), U("some_password")); // WinHTTP requires non-empty password + client_config.set_credentials(cred); + http_client client(m_uri, client_config); + const method mtd = methods::POST; - std::vector msg_body; - msg_body.push_back('a'); + std::vector msg_body; + msg_body.push_back('a'); - http_request msg(mtd); - msg.set_body(streams::container_stream>::open_istream(std::move(msg_body))); + http_request msg(mtd); + msg.set_body(streams::container_stream>::open_istream(std::move(msg_body))); - auto replyFunc = [&](test_request *p_request) + auto replyFunc = [&](test_request *p_request) { utility::string_t contents(U("a")); http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("application/octet-stream"), contents); @@ -185,24 +192,26 @@ TEST_FIXTURE(uri_address, proxy_auth_unknown_contentlength, "Ignore:Linux", "88" p_request->reply(200); }; - scoped.server()->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, mtd, U("/")); + t = scoped.server()->next_request().then([&](test_request *p_request) + { + http_asserts::assert_test_request_equals(p_request, mtd, U("/")); - // Auth header - std::map headers; - headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); + // Auth header + std::map headers; + headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); - // unauthorized - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); + // unauthorized + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); - }).then([&scoped, replyFunc]() - { - // Client resent the request - scoped.server()->next_request().then(replyFunc); - }); + }).then([&scoped, replyFunc]() + { + // Client resent the request + return scoped.server()->next_request().then(replyFunc); + }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + } + t.get(); } // Accessing a server that returns 401 with an empty user name should not resend the request with an empty password @@ -211,7 +220,7 @@ TEST_FIXTURE(uri_address, empty_username_password) test_http_server::scoped_server scoped(m_uri); http_client client(m_uri); - scoped.server()->next_request().then([&](test_request *p_request) + auto t = scoped.server()->next_request().then([&](test_request *p_request) { std::map headers; headers[U("h1")] = U("data1"); @@ -227,6 +236,7 @@ TEST_FIXTURE(uri_address, empty_username_password) VERIFY_ARE_EQUAL(status_codes::Unauthorized, response.status_code()); VERIFY_ARE_EQUAL(str_body[0], 'a'); VERIFY_ARE_EQUAL(h1, U("data1")); + t.get(); } #endif @@ -235,53 +245,57 @@ TEST_FIXTURE(uri_address, empty_username_password) // We're making sure the error is reported properly, and the response data from the second response is received TEST_FIXTURE(uri_address, error_after_valid_credentials, "Ignore:Linux", "89", "Ignore:Apple", "89") { - web::http::uri uri(U("http://localhost:34569/")); - test_http_server::scoped_server scoped(uri); - http_client_config client_config; - web::credentials cred(U("some_user"), U("some_password")); - client_config.set_credentials(cred); - http_client client(uri, client_config); - - auto replyFunc = [&](test_request *p_request) + pplx::task t; + { + web::http::uri uri(U("http://localhost:34569/")); + test_http_server::scoped_server scoped(uri); + http_client_config client_config; + web::credentials cred(U("some_user"), U("some_password")); + client_config.set_credentials(cred); + http_client client(uri, client_config); + + auto replyFunc = [&](test_request *p_request) { std::map headers; // Auth header headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); headers[U("h1")] = U("data2"); // still unauthorized after the user has resent the request with the credentials - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers, "def" ); + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers, "def"); }; - scoped.server()->next_request().then([&](test_request *p_request) - { - std::map headers; - headers[U("h1")] = U("data1"); - // Auth header - headers[U("WWW-Authenticate")] = U("Basic realm = \"myRealm\""); - // unauthorized - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers, "abc" ); - }).then([&scoped, &replyFunc]() - { - // Client resent the request - scoped.server()->next_request().then(replyFunc); - }) + t = scoped.server()->next_request().then([&](test_request *p_request) + { + std::map headers; + headers[U("h1")] = U("data1"); + // Auth header + headers[U("WWW-Authenticate")] = U("Basic realm = \"myRealm\""); + // unauthorized + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers, "abc"); + }).then([&scoped, &replyFunc]() + { + // Client resent the request + return scoped.server()->next_request().then(replyFunc); + }) #ifdef __cplusplus_winrt - .then([&scoped, &replyFunc]() - { - // in winrt, client resent the request again - scoped.server()->next_request().then(replyFunc); - }) + .then([&scoped, &replyFunc]() + { + // in winrt, client resent the request again + return scoped.server()->next_request().then(replyFunc); + }) #endif - ; + ; - http_response response = client.request(methods::GET).get(); - auto str_body = response.extract_vector().get(); - auto h1 = response.headers()[U("h1")]; - VERIFY_ARE_EQUAL(status_codes::Unauthorized, response.status_code()); - VERIFY_ARE_EQUAL(str_body[0], 'd'); - VERIFY_ARE_EQUAL(str_body[1], 'e'); - VERIFY_ARE_EQUAL(str_body[2], 'f'); - VERIFY_ARE_EQUAL(h1, U("data2")); + http_response response = client.request(methods::GET).get(); + auto str_body = response.extract_vector().get(); + auto h1 = response.headers()[U("h1")]; + VERIFY_ARE_EQUAL(status_codes::Unauthorized, response.status_code()); + VERIFY_ARE_EQUAL(str_body[0], 'd'); + VERIFY_ARE_EQUAL(str_body[1], 'e'); + VERIFY_ARE_EQUAL(str_body[2], 'f'); + VERIFY_ARE_EQUAL(h1, U("data2")); + } + t.get(); } @@ -471,7 +485,7 @@ TEST_FIXTURE(server_properties, set_user_options, "Requires", "Server;UserName;P VERIFY_ARE_EQUAL(200, client.request(request).get().status_code()); } -TEST_FIXTURE(uri_address, auth_producer_comsumer_buffer) +TEST_FIXTURE(uri_address, auth_producer_consumer_buffer) { auto buf = streams::producer_consumer_buffer(); buf.putc('a').get(); @@ -490,27 +504,27 @@ TEST_FIXTURE(uri_address, auth_producer_comsumer_buffer) http_client client(m_uri, config); + pplx::task t, t2; test_http_server::scoped_server scoped(m_uri); - auto replyFunc = [&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("application/octet-stream"), U("aaaa")); - p_request->reply(200); - }; - - scoped.server()->next_request().then([&](test_request *p_request) + t = scoped.server()->next_request().then([&](test_request *p_request) { http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("application/octet-stream"), U("aaaa")); std::map headers; headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); - }) - .then([&scoped, replyFunc](){ - scoped.server()->next_request().then(replyFunc); + }); + t2 = scoped.server()->next_request().then([&](test_request *p_request) + { + http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("application/octet-stream"), U("aaaa")); + p_request->reply(200); }); http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + scoped.server()->close(); + VERIFY_NO_THROWS(t.get()); + VERIFY_NO_THROWS(t2.get()); } TEST_FIXTURE(uri_address, auth_producer_comsumer_buffer_fail_no_cred) @@ -526,18 +540,21 @@ TEST_FIXTURE(uri_address, auth_producer_comsumer_buffer_fail_no_cred) http_client client(m_uri); - test_http_server::scoped_server scoped(m_uri); - - scoped.server()->next_request().then([&](test_request *p_request) + pplx::task t; { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("application/octet-stream"), U("aaaa")); - std::map headers; - headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); + test_http_server::scoped_server scoped(m_uri); + t = scoped.server()->next_request().then([&](test_request *p_request) + { + http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("application/octet-stream"), U("aaaa")); + std::map headers; + headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); - }); + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); + }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::Unauthorized); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::Unauthorized); + } + t.get(); } TEST_FIXTURE(uri_address, auth_producer_comsumer_buffer_fail) @@ -553,31 +570,33 @@ TEST_FIXTURE(uri_address, auth_producer_comsumer_buffer_fail) config.set_credentials(web::credentials(U("USERNAME"), U("PASSWORD"))); http_client client(m_uri, config); - - test_http_server::scoped_server scoped(m_uri); - - auto replyFunc = [&](test_request *p_request) + pplx::task t; { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("application/octet-stream"), U("a")); - std::map headers; - headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld2\""); + test_http_server::scoped_server scoped(m_uri); - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); - }; + auto replyFunc = [&](test_request *p_request) + { + http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("application/octet-stream"), U("a")); + std::map headers; + headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld2\""); - scoped.server()->next_request().then([&](test_request *p_request) - { - http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("application/octet-stream"), U("a")); - std::map headers; - headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); + }; - p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); - }) - .then([&scoped, replyFunc](){ - scoped.server()->next_request().then(replyFunc); - }); + t = scoped.server()->next_request().then([&](test_request *p_request) + { + http_asserts::assert_test_request_equals(p_request, methods::POST, U("/"), U("application/octet-stream"), U("a")); + std::map headers; + headers[U("WWW-Authenticate")] = U("Basic realm = \"WallyWorld\""); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::Unauthorized); + p_request->reply(status_codes::Unauthorized, U("Authentication Failed"), headers); + }).then([&scoped, replyFunc](){ + return scoped.server()->next_request().then(replyFunc); + }); + + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::Unauthorized); + } + VERIFY_NO_THROWS(t.get()); } #endif diff --git a/Release/tests/functional/http/client/building_request_tests.cpp b/Release/tests/functional/http/client/building_request_tests.cpp index bf09a82de6..a12ddfe8fc 100644 --- a/Release/tests/functional/http/client/building_request_tests.cpp +++ b/Release/tests/functional/http/client/building_request_tests.cpp @@ -32,6 +32,7 @@ SUITE(building_request_tests) TEST_FIXTURE(uri_address, simple_values) { test_http_server::scoped_server scoped(m_uri); + pplx::task t1, t2; test_http_server * p_server = scoped.server(); http_client client(m_uri); @@ -44,7 +45,7 @@ TEST_FIXTURE(uri_address, simple_values) const utility::string_t custom_path1 = U("/hey/custom/path"); msg.set_request_uri(custom_path1); VERIFY_ARE_EQUAL(custom_path1, msg.relative_uri().to_string()); - p_server->next_request().then([&](test_request *p_request) + t1 = p_server->next_request().then([&](test_request *p_request) { http_asserts::assert_test_request_equals(p_request, method, custom_path1); p_request->reply(200); @@ -58,12 +59,15 @@ TEST_FIXTURE(uri_address, simple_values) const utility::string_t custom_path2 = U("/yes/you/there"); msg.set_request_uri(custom_path2); VERIFY_ARE_EQUAL(custom_path2, msg.relative_uri().to_string()); - p_server->next_request().then([&](test_request *p_request) + t2 = p_server->next_request().then([&](test_request *p_request) { http_asserts::assert_test_request_equals(p_request, method, custom_path2); p_request->reply(200); }); http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + p_server->close(); + try { t1.get(); } catch (...) { VERIFY_ARE_EQUAL(0, 1, "t1 failed"); } + try { t2.get(); } catch (...) { VERIFY_ARE_EQUAL(0, 2, "t2 failed"); } } TEST_FIXTURE(uri_address, body_types) @@ -262,37 +266,39 @@ TEST_FIXTURE(uri_address, set_content_length_locale, "Ignore:Android", "Locale u TEST_FIXTURE(uri_address, set_port_locale, "Ignore:Android", "Locale unsupported on Android") { + std::locale changedLocale; + try + { +#ifdef _WIN32 + changedLocale = std::locale("fr-FR"); +#else + changedLocale = std::locale("fr_FR.UTF-8"); +#endif + } + catch (const std::exception &) + { + // Silently pass if locale isn't installed on machine. + return; + } + tests::common::utilities::locale_guard loc(changedLocale); + test_http_server::scoped_server scoped(m_uri); + pplx::task t; http_client client(m_uri); utility::string_t data(U("STRING data 1000")); - scoped.server()->next_request().then([&](test_request *p_request) + t = scoped.server()->next_request().then([&](test_request *p_request) { http_asserts::assert_test_request_equals(p_request, methods::PUT, U("/"), U("text/plain; charset=utf-8"), data); p_request->reply(200); }); - { - std::locale changedLocale; - try - { -#ifdef _WIN32 - changedLocale = std::locale("fr-FR"); -#else - changedLocale = std::locale("fr_FR.UTF-8"); -#endif - } - catch (const std::exception &) - { - // Silently pass if locale isn't installed on machine. - return; - } + http_request msg(methods::PUT); + msg.set_body(data); + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - tests::common::utilities::locale_guard loc(changedLocale); - http_request msg(methods::PUT); - msg.set_body(data); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); - } + scoped.server()->close(); + t.get(); } TEST_FIXTURE(uri_address, reuse_request) diff --git a/Release/tests/functional/http/client/connections_and_errors.cpp b/Release/tests/functional/http/client/connections_and_errors.cpp index 9bbd4e626a..b535dc5a64 100644 --- a/Release/tests/functional/http/client/connections_and_errors.cpp +++ b/Release/tests/functional/http/client/connections_and_errors.cpp @@ -31,43 +31,50 @@ namespace tests { namespace functional { namespace http { namespace client { // Test implementation for pending_requests_after_client. static void pending_requests_after_client_impl(const uri &address) { - test_http_server::scoped_server scoped(address); - const method mtd = methods::GET; - - const size_t num_requests = 10; - std::vector> responses; + std::vector> completed_requests; { - http_client client(address); + test_http_server::scoped_server scoped(address); + const method mtd = methods::GET; - // send requests. - for(size_t i = 0; i < num_requests; ++i) - { - responses.push_back(client.request(mtd)); - } - } + const size_t num_requests = 10; - // send responses. - for(size_t i = 0; i < num_requests; ++i) - { - scoped.server()->next_request().then([&](test_request *request) + std::vector> requests = scoped.server()->next_requests(num_requests); + std::vector> responses; { - http_asserts::assert_test_request_equals(request, mtd, U("/")); - VERIFY_ARE_EQUAL(0u, request->reply(status_codes::OK)); - }); - } + http_client client(address); - // verify responses. - for(size_t i = 0; i < num_requests; ++i) - { - try + // send requests. + for (size_t i = 0; i < num_requests; ++i) + { + responses.push_back(client.request(mtd)); + } + } + + // send responses. + for (size_t i = 0; i < num_requests; ++i) { - http_asserts::assert_response_equals(responses[i].get(), status_codes::OK); + completed_requests.push_back(requests[i].then([&](test_request *request) + { + http_asserts::assert_test_request_equals(request, mtd, U("/")); + VERIFY_ARE_EQUAL(0u, request->reply(status_codes::OK)); + })); } - catch (...) + + // verify responses. + for (size_t i = 0; i < num_requests; ++i) { - VERIFY_IS_TRUE(false); + try + { + http_asserts::assert_response_equals(responses[i].get(), status_codes::OK); + } + catch (...) + { + VERIFY_IS_TRUE(false); + } } } + for (auto&& req : completed_requests) + req.get(); } SUITE(connections_and_errors) @@ -81,7 +88,9 @@ TEST_FIXTURE(uri_address, pending_requests_after_client) TEST_FIXTURE(uri_address, server_doesnt_exist) { - http_client client(m_uri); + http_client_config config; + config.set_timeout(std::chrono::seconds(1)); + http_client client(m_uri, config); VERIFY_THROWS_HTTP_ERROR_CODE(client.request(methods::GET).wait(), std::errc::host_unreachable); } @@ -97,17 +106,23 @@ TEST_FIXTURE(uri_address, open_failure) TEST_FIXTURE(uri_address, server_close_without_responding) { - test_http_server server(m_uri); - VERIFY_ARE_EQUAL(0u, server.open()); - http_client client(m_uri); + http_client_config config; + config.set_timeout(utility::seconds(1)); + + http_client client(m_uri, config); + test_http_server::scoped_server server(m_uri); + auto t = server.server()->next_request(); // Send request. - auto request = client.request(methods::PUT); + auto response = client.request(methods::PUT); + + // Wait for request + VERIFY_NO_THROWS(t.get()); // Close server connection. - server.wait_for_request(); - server.close(); - VERIFY_THROWS_HTTP_ERROR_CODE(request.wait(), std::errc::connection_aborted); + server.server()->close(); + + VERIFY_THROWS_HTTP_ERROR_CODE(response.wait(), std::errc::connection_aborted); // Try sending another request. VERIFY_THROWS_HTTP_ERROR_CODE(client.request(methods::GET).wait(), std::errc::host_unreachable); @@ -116,6 +131,7 @@ TEST_FIXTURE(uri_address, server_close_without_responding) TEST_FIXTURE(uri_address, request_timeout) { test_http_server::scoped_server scoped(m_uri); + auto t = scoped.server()->next_request(); http_client_config config; config.set_timeout(utility::seconds(1)); @@ -128,22 +144,29 @@ TEST_FIXTURE(uri_address, request_timeout) #else VERIFY_THROWS_HTTP_ERROR_CODE(responseTask.get(), std::errc::timed_out); #endif + t.get(); } TEST_FIXTURE(uri_address, request_timeout_microsecond) { - test_http_server::scoped_server scoped(m_uri); - http_client_config config; - config.set_timeout(std::chrono::microseconds(500)); + pplx::task t; + { + test_http_server::scoped_server scoped(m_uri); + t = scoped.server()->next_request(); + http_client_config config; + config.set_timeout(std::chrono::microseconds(500)); - http_client client(m_uri, config); - auto responseTask = client.request(methods::GET); + http_client client(m_uri, config); + auto responseTask = client.request(methods::GET); #ifdef __APPLE__ - // CodePlex 295 - VERIFY_THROWS(responseTask.get(), http_exception); + // CodePlex 295 + VERIFY_THROWS(responseTask.get(), http_exception); #else - VERIFY_THROWS_HTTP_ERROR_CODE(responseTask.get(), std::errc::timed_out); + VERIFY_THROWS_HTTP_ERROR_CODE(responseTask.get(), std::errc::timed_out); #endif + } + try { t.get(); } + catch (...) {} } TEST_FIXTURE(uri_address, invalid_method) @@ -320,14 +343,15 @@ TEST_FIXTURE(uri_address, cancel_after_body) TEST_FIXTURE(uri_address, cancel_with_error) { - test_http_server server(m_uri); - VERIFY_ARE_EQUAL(0, server.open()); http_client c(m_uri); - pplx::cancellation_token_source source; + pplx::task responseTask; + { + test_http_server::scoped_server server(m_uri); + pplx::cancellation_token_source source; - auto responseTask = c.request(methods::GET, U("/"), source.get_token()); - source.cancel(); - VERIFY_ARE_EQUAL(0, server.close()); + responseTask = c.request(methods::GET, U("/"), source.get_token()); + source.cancel(); + } // All errors after cancellation are ignored. VERIFY_THROWS_HTTP_ERROR_CODE(responseTask.get(), std::errc::operation_canceled); @@ -408,7 +432,7 @@ TEST_FIXTURE(uri_address, cancel_bad_port) // Send request. http_client_config config; - config.set_timeout(std::chrono::milliseconds(500)); + config.set_timeout(std::chrono::milliseconds(1000)); http_client c(uri, config); web::http::http_request r; auto cts = pplx::cancellation_token_source(); diff --git a/Release/tests/functional/http/client/multiple_requests.cpp b/Release/tests/functional/http/client/multiple_requests.cpp index 42b8840629..0e643eb3e9 100644 --- a/Release/tests/functional/http/client/multiple_requests.cpp +++ b/Release/tests/functional/http/client/multiple_requests.cpp @@ -53,6 +53,13 @@ TEST_FIXTURE(uri_address, requests_with_data) const method method = methods::PUT; const web::http::status_code code = status_codes::OK; + std::vector> reqs; + // response to requests + for (size_t i = 0; i < num_requests; ++i) + { + reqs.push_back(scoped.server()->next_request()); + } + // send requests std::vector> responses; for(size_t i = 0; i < num_requests; ++i) @@ -62,13 +69,9 @@ TEST_FIXTURE(uri_address, requests_with_data) responses.push_back(client.request(msg)); } - // Wait a bit to let requests get queued up in WinHTTP. - os_utilities::sleep(500); - - // response to requests - for(size_t i = 0; i < num_requests; ++i) + for (auto&& requestTask : reqs) { - test_request *request = scoped.server()->wait_for_request(); + auto request = requestTask.get(); http_asserts::assert_test_request_equals(request, method, U("/"), U("text/plain"), to_string_t(request_body)); VERIFY_ARE_EQUAL(0u, request->reply(code)); } @@ -101,6 +104,9 @@ TEST_FIXTURE(uri_address, responses_with_data) std::map headers; headers[U("Content-Type")] = U("text/plain"); + // response to requests + auto requestTasks = scoped.server()->next_requests(num_requests); + // send requests std::vector> responses; for(size_t i = 0; i < num_requests; ++i) @@ -111,7 +117,7 @@ TEST_FIXTURE(uri_address, responses_with_data) // response to requests for(size_t i = 0; i < num_requests; ++i) { - test_request *request = scoped.server()->wait_for_request(); + test_request *request = requestTasks[i].get(); http_asserts::assert_test_request_equals(request, method, U("/")); VERIFY_ARE_EQUAL(0u, request->reply(code, U(""), headers, request_body)); } diff --git a/Release/tests/functional/http/client/outside_tests.cpp b/Release/tests/functional/http/client/outside_tests.cpp index f10b862ba7..35d0f6e867 100644 --- a/Release/tests/functional/http/client/outside_tests.cpp +++ b/Release/tests/functional/http/client/outside_tests.cpp @@ -171,7 +171,9 @@ TEST(server_cert_expired) { handle_timeout([] { - http_client client(U("https://tv.eurosport.com/")); + http_client_config config; + config.set_timeout(std::chrono::seconds(1)); + http_client client(U("https://tv.eurosport.com/"), config); auto requestTask = client.request(methods::GET); VERIFY_THROWS(requestTask.get(), http_exception); }); @@ -187,6 +189,7 @@ TEST(ignore_server_cert_invalid, { http_client_config config; config.set_validate_certificates(false); + config.set_timeout(std::chrono::seconds(1)); http_client client(U("https://www.pcwebshop.co.uk/"), config); auto request = client.request(methods::GET).get(); diff --git a/Release/tests/functional/http/client/progress_handler_tests.cpp b/Release/tests/functional/http/client/progress_handler_tests.cpp index 4bf29247f6..4b9568c36e 100644 --- a/Release/tests/functional/http/client/progress_handler_tests.cpp +++ b/Release/tests/functional/http/client/progress_handler_tests.cpp @@ -292,7 +292,7 @@ TEST_FIXTURE(uri_address, set_progress_handler_request_timeout) }); msg.set_body(data); - + auto t = scoped.server()->next_request(); auto response = client.request(msg); #ifdef __APPLE__ @@ -306,6 +306,7 @@ TEST_FIXTURE(uri_address, set_progress_handler_request_timeout) // We don't have very precise control over how much of the message is transferred // before the exception occurs, so we can't make an exact comparison here. VERIFY_IS_TRUE(calls >= 2); + t.get(); } TEST_FIXTURE(uri_address, upload_nobody_exception) @@ -314,7 +315,7 @@ TEST_FIXTURE(uri_address, upload_nobody_exception) http_client client(m_uri); http_request msg(methods::GET); - scoped.server()->next_request().then([&](test_request *p_request) + auto t = scoped.server()->next_request().then([&](test_request *p_request) { p_request->reply(200, utility::string_t(U("OK"))); }); @@ -326,11 +327,8 @@ TEST_FIXTURE(uri_address, upload_nobody_exception) }); VERIFY_THROWS(client.request(msg).get(), std::invalid_argument); - - // Codeplex 328. -#if !defined(_WIN32) - tests::common::utilities::os_utilities::sleep(1000); -#endif + + t.get(); } TEST_FIXTURE(uri_address, download_nobody_exception) @@ -359,7 +357,6 @@ TEST_FIXTURE(uri_address, download_nobody_exception) TEST_FIXTURE(uri_address, data_upload_exception) { - test_http_server::scoped_server scoped(m_uri); http_client client(m_uri); http_request msg(methods::PUT); msg.set_body(U("A")); @@ -369,12 +366,14 @@ TEST_FIXTURE(uri_address, data_upload_exception) throw std::invalid_argument("fake error"); }); - VERIFY_THROWS(client.request(msg).get(), std::invalid_argument); - - // Codeplex 328. -#if !defined(_WIN32) - tests::common::utilities::os_utilities::sleep(1000); -#endif + pplx::task t; + { + test_http_server::scoped_server scoped(m_uri); + t = scoped.server()->next_request(); + VERIFY_THROWS(client.request(msg).get(), std::invalid_argument); + } + try { t.get(); } + catch (const std::runtime_error&) { /* It is ok if the request does not complete before the server is shutdown */ } } TEST_FIXTURE(uri_address, data_download_exception, "Ignore:Windows", "395") @@ -383,7 +382,7 @@ TEST_FIXTURE(uri_address, data_download_exception, "Ignore:Windows", "395") http_client client(m_uri); http_request msg(methods::GET); - scoped.server()->next_request().then([&](test_request *p_request) + auto t = scoped.server()->next_request().then([&](test_request *p_request) { std::string resp_data("abc"); std::map headers; @@ -412,6 +411,7 @@ TEST_FIXTURE(uri_address, data_download_exception, "Ignore:Windows", "395") { // Expected. } + t.get(); } } diff --git a/Release/tests/functional/http/listener/connections_and_errors.cpp b/Release/tests/functional/http/listener/connections_and_errors.cpp index 9aade80c42..124ea7f829 100644 --- a/Release/tests/functional/http/listener/connections_and_errors.cpp +++ b/Release/tests/functional/http/listener/connections_and_errors.cpp @@ -378,6 +378,9 @@ int verify_http_exception(Func f) TEST_FIXTURE(uri_address, request_content_ready_timeout, "Ignore:Linux", "Unsuitable until 813276", "Ignore:Apple", "Unsuitable until 813276") { +#if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) + throw std::runtime_error("Unsuitable until 813276 -- http_listener on ASIO does not support timeouts nor chunk sizes"); +#endif http_listener_config config; config.set_timeout(utility::seconds(1)); http_listener listener(m_uri, config); From 33edea3fd20eb476eaeebd6bc8ef00f95142851b Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 19 Apr 2017 12:33:47 -0700 Subject: [PATCH 050/438] Add _SCL_SECURE_NO_WARNINGS because websockets++ does not compile cleanly --- Release/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 7d6ee6a947..5d1e036c2c 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -111,7 +111,7 @@ elseif(ANDROID) ) elseif(UNIX) # This includes OSX elseif(WIN32) - add_definitions(-DUNICODE -D_UNICODE -D_WIN32_WINNT=0x0600) + add_definitions(-DUNICODE -D_UNICODE -D_WIN32_WINNT=0x0600 -DWIN32 -D_SCL_SECURE_NO_WARNINGS) if(NOT BUILD_SHARED_LIBS) # This causes cmake to not link the test libraries separately, but instead hold onto their object files. @@ -120,7 +120,7 @@ elseif(WIN32) else() set(Casablanca_DEFINITIONS "" CACHE INTERNAL "Definitions for consume casablanca library") endif() - add_definitions(${Casablanca_DEFINITIONS} -D_WINSOCK_DEPRECATED_NO_WARNINGS -DWIN32) + add_definitions(${Casablanca_DEFINITIONS} -D_WINSOCK_DEPRECATED_NO_WARNINGS) else() message(FATAL_ERROR "-- Unsupported Build Platform.") endif() From 38d916a638982716a3ca2ec73b1221e5da4d706d Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 19 Apr 2017 12:43:15 -0700 Subject: [PATCH 051/438] Rename listener::details::connection -> listener::details::asio_server_connection. Move implementation to internal cpp instead of header file. Use return values to track async lifetime and ensure proper cleanup. --- .../cpprest/details/http_server_asio.h | 84 +--- .../src/http/listener/http_server_asio.cpp | 438 ++++++++++++------ 2 files changed, 308 insertions(+), 214 deletions(-) diff --git a/Release/include/cpprest/details/http_server_asio.h b/Release/include/cpprest/details/http_server_asio.h index 4ad37f404b..13c4d7e51a 100644 --- a/Release/include/cpprest/details/http_server_asio.h +++ b/Release/include/cpprest/details/http_server_asio.h @@ -46,88 +46,12 @@ struct linux_request_context : web::http::details::_http_server_context linux_request_context& operator=(const linux_request_context&); }; -class hostport_listener; - -class connection -{ -private: - typedef void (connection::*ResponseFuncPtr) (const http_response &response, const boost::system::error_code& ec); - - std::unique_ptr m_socket; - boost::asio::streambuf m_request_buf; - boost::asio::streambuf m_response_buf; - http_linux_server* m_p_server; - hostport_listener* m_p_parent; - http_request m_request; - size_t m_read, m_write; - size_t m_read_size, m_write_size; - bool m_close; - bool m_chunked; - std::atomic m_refs; // track how many threads are still referring to this - - std::unique_ptr m_ssl_context; - std::unique_ptr> m_ssl_stream; - -public: - connection(std::unique_ptr socket, http_linux_server* server, hostport_listener* parent, bool is_https, const std::function& ssl_context_callback) - : m_socket(std::move(socket)) - , m_request_buf() - , m_response_buf() - , m_p_server(server) - , m_p_parent(parent) - , m_close(false) - , m_refs(1) - { - if (is_https) - { - m_ssl_context = utility::details::make_unique(boost::asio::ssl::context::sslv23); - if (ssl_context_callback) - { - ssl_context_callback(*m_ssl_context); - } - m_ssl_stream = utility::details::make_unique>(*m_socket, *m_ssl_context); - - m_ssl_stream->async_handshake(boost::asio::ssl::stream_base::server, [this](const boost::system::error_code&) { this->start_request_response(); }); - } - else - { - start_request_response(); - } - } - - connection(const connection&) = delete; - connection& operator=(const connection&) = delete; - - void close(); - -private: - void start_request_response(); - void handle_http_line(const boost::system::error_code& ec); - void handle_headers(); - void handle_body(const boost::system::error_code& ec); - void handle_chunked_header(const boost::system::error_code& ec); - void handle_chunked_body(const boost::system::error_code& ec, int toWrite); - void dispatch_request_to_listener(); - void do_response(bool bad_request); - void async_write(ResponseFuncPtr response_func_ptr, const http_response &response); - template - void async_read(CompletionCondition &&condition, Handler &&read_handler); - void async_read_until(); - template - void async_read_until_buffersize(size_t size, const ReadHandler &handler); - void async_process_response(http_response response); - void cancel_sending_response_with_error(const http_response &response, const std::exception_ptr &); - void handle_headers_written(const http_response &response, const boost::system::error_code& ec); - void handle_write_large_response(const http_response &response, const boost::system::error_code& ec); - void handle_write_chunked_response(const http_response &response, const boost::system::error_code& ec); - void handle_response_written(const http_response &response, const boost::system::error_code& ec); - void finish_request_response(); -}; +class asio_server_connection; class hostport_listener { private: - friend class connection; + friend class asio_server_connection; std::unique_ptr m_acceptor; std::map m_listeners; @@ -135,7 +59,7 @@ class hostport_listener std::mutex m_connections_lock; pplx::extensibility::event_t m_all_connections_complete; - std::set m_connections; + std::set m_connections; http_linux_server* m_p_server; @@ -194,7 +118,7 @@ struct iequal_to class http_linux_server : public web::http::experimental::details::http_server { private: - friend class http::experimental::listener::details::connection; + friend class http::experimental::listener::details::asio_server_connection; pplx::extensibility::reader_writer_lock_t m_listeners_lock; std::map, iequal_to> m_listeners; diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 9ec7c66b6f..76645c1054 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -145,6 +145,154 @@ struct crlfcrlf_nonascii_searcher_t return std::make_pair(excluded, false); } } crlfcrlf_nonascii_searcher; + +// These structures serve as proof witnesses +struct will_erase_from_parent_t {}; +struct will_deref_and_erase_t {}; +struct will_deref_t {}; + +class asio_server_connection +{ +private: + + typedef void (asio_server_connection::*ResponseFuncPtr) (const http_response &response, const boost::system::error_code& ec); + + std::unique_ptr m_socket; + boost::asio::streambuf m_request_buf; + boost::asio::streambuf m_response_buf; + http_linux_server* m_p_server; + hostport_listener* m_p_parent; + http_request m_request; + size_t m_read, m_write; + size_t m_read_size, m_write_size; + bool m_close; + bool m_chunked; + std::atomic m_refs; // track how many threads are still referring to this + + using ssl_stream = boost::asio::ssl::stream; + + std::unique_ptr m_ssl_context; + std::unique_ptr m_ssl_stream; + +public: + asio_server_connection(std::unique_ptr socket, http_linux_server* server, hostport_listener* parent) + : m_socket(std::move(socket)) + , m_request_buf() + , m_response_buf() + , m_p_server(server) + , m_p_parent(parent) + , m_close(false) + , m_refs(1) + { + } + + will_deref_and_erase_t start(bool is_https, const std::function& ssl_context_callback) + { + if (is_https) + { + m_ssl_context = utility::details::make_unique(boost::asio::ssl::context::sslv23); + if (ssl_context_callback) + { + ssl_context_callback(*m_ssl_context); + } + m_ssl_stream = utility::details::make_unique(*m_socket, *m_ssl_context); + + m_ssl_stream->async_handshake(boost::asio::ssl::stream_base::server, [this](const boost::system::error_code&) + { + (will_deref_and_erase_t)this->start_request_response(); + }); + return will_deref_and_erase_t{}; + } + else + { + return start_request_response(); + } + } + + void close(); + + asio_server_connection(const asio_server_connection&) = delete; + asio_server_connection& operator=(const asio_server_connection&) = delete; + +private: + ~asio_server_connection() = default; + + will_deref_and_erase_t start_request_response(); + will_deref_and_erase_t handle_http_line(const boost::system::error_code& ec); + will_deref_and_erase_t handle_headers(); + will_deref_t handle_body(const boost::system::error_code& ec); + will_deref_t handle_chunked_header(const boost::system::error_code& ec); + will_deref_t handle_chunked_body(const boost::system::error_code& ec, int toWrite); + will_deref_and_erase_t dispatch_request_to_listener(); + will_erase_from_parent_t do_response() + { + ++m_refs; + m_request.get_response().then([=](pplx::task r_task) + { + http::http_response response; + try + { + response = r_task.get(); + } + catch (...) + { + response = http::http_response(status_codes::InternalError); + } + + serialize_headers(response); + + // before sending response, the full incoming message need to be processed. + return m_request.content_ready().then([=](pplx::task) + { + (will_deref_and_erase_t)this->async_write(&asio_server_connection::handle_headers_written, response); + }); + }); + return will_erase_from_parent_t{}; + } + will_erase_from_parent_t do_bad_response() + { + ++m_refs; + m_request.get_response().then([=](pplx::task r_task) + { + http::http_response response; + try + { + response = r_task.get(); + } + catch (...) + { + response = http::http_response(status_codes::InternalError); + } + + // before sending response, the full incoming message need to be processed. + serialize_headers(response); + + (will_deref_and_erase_t)async_write(&asio_server_connection::handle_headers_written, response); + }); + return will_erase_from_parent_t{}; + } + + will_deref_t async_handle_chunked_header(); + template + void async_read_until_buffersize(size_t size, const ReadHandler &handler); + void serialize_headers(http_response response); + will_deref_and_erase_t cancel_sending_response_with_error(const http_response &response, const std::exception_ptr &); + will_deref_and_erase_t handle_headers_written(const http_response &response, const boost::system::error_code& ec); + will_deref_and_erase_t handle_write_large_response(const http_response &response, const boost::system::error_code& ec); + will_deref_and_erase_t handle_write_chunked_response(const http_response &response, const boost::system::error_code& ec); + will_deref_and_erase_t handle_response_written(const http_response &response, const boost::system::error_code& ec); + will_deref_and_erase_t finish_request_response(); + + using WriteFunc = decltype(&asio_server_connection::handle_headers_written); + will_deref_and_erase_t async_write(WriteFunc response_func_ptr, const http_response &response); + + inline will_deref_t deref() + { + if (--m_refs == 0) delete this; + return will_deref_t{}; + } +}; + }}}}} namespace boost @@ -183,7 +331,7 @@ void hostport_listener::start() m_acceptor->async_accept(*socket, boost::bind(&hostport_listener::on_accept, this, socket, placeholders::error)); } -void connection::close() +void asio_server_connection::close() { m_close = true; auto sock = m_socket.get(); @@ -197,7 +345,7 @@ void connection::close() m_request._reply_if_not_already(status_codes::InternalError); } -void connection::start_request_response() +will_deref_and_erase_t asio_server_connection::start_request_response() { m_read_size = 0; m_read = 0; @@ -207,16 +355,17 @@ void connection::start_request_response() { boost::asio::async_read_until(*m_ssl_stream, m_request_buf, CRLFCRLF, [this](const boost::system::error_code& ec, std::size_t) { - this->handle_http_line(ec); + (will_deref_and_erase_t)this->handle_http_line(ec); }); } else { boost::asio::async_read_until(*m_socket, m_request_buf, crlfcrlf_nonascii_searcher, [this](const boost::system::error_code& ec, std::size_t) { - this->handle_http_line(ec); + (will_deref_and_erase_t)this->handle_http_line(ec); }); } + return will_deref_and_erase_t{}; } void hostport_listener::on_accept(ip::tcp::socket* socket, const boost::system::error_code& ec) @@ -225,9 +374,13 @@ void hostport_listener::on_accept(ip::tcp::socket* socket, const boost::system:: if (!ec) { + auto conn = new asio_server_connection(std::move(usocket), m_p_server, this); + std::lock_guard lock(m_connections_lock); - m_connections.insert(new connection(std::move(usocket), m_p_server, this, m_is_https, m_ssl_context_callback)); - m_all_connections_complete.reset(); + m_connections.insert(conn); + conn->start(m_is_https, m_ssl_context_callback); + if (m_connections.size() == 1) + m_all_connections_complete.reset(); if (m_acceptor) { @@ -238,7 +391,7 @@ void hostport_listener::on_accept(ip::tcp::socket* socket, const boost::system:: } } -void connection::handle_http_line(const boost::system::error_code& ec) +will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::system::error_code& ec) { m_request = http_request::_create_request(std::unique_ptr(new linux_request_context())); if (ec) @@ -251,13 +404,15 @@ void connection::handle_http_line(const boost::system::error_code& ec) ec == boost::asio::error::timed_out // connection timed out ) { - finish_request_response(); + return finish_request_response(); } else { m_request._reply_if_not_already(status_codes::BadRequest); m_close = true; - do_response(true); + (will_erase_from_parent_t)do_bad_response(); + (will_deref_t)deref(); + return will_deref_and_erase_t{}; } } else @@ -292,8 +447,9 @@ void connection::handle_http_line(const boost::system::error_code& ec) { m_request.reply(status_codes::BadRequest); m_close = true; - do_response(true); - return; + (will_erase_from_parent_t)do_bad_response(); + (will_deref_t)deref(); + return will_deref_and_erase_t{}; } m_request.set_method(http_verb); @@ -307,8 +463,9 @@ void connection::handle_http_line(const boost::system::error_code& ec) { m_request.reply(status_codes::BadRequest); m_close = true; - do_response(true); - return; + (will_erase_from_parent_t)do_bad_response(); + (will_deref_t)deref(); + return will_deref_and_erase_t{}; } // Get the path - remove the version portion and prefix space @@ -320,8 +477,9 @@ void connection::handle_http_line(const boost::system::error_code& ec) { m_request.reply(status_codes::BadRequest, e.what()); m_close = true; - do_response(true); - return; + (will_erase_from_parent_t)do_bad_response(); + (will_deref_t)deref(); + return will_deref_and_erase_t{}; } // Get the version @@ -332,11 +490,11 @@ void connection::handle_http_line(const boost::system::error_code& ec) m_close = true; } - handle_headers(); + return handle_headers(); } } -void connection::handle_headers() +will_deref_and_erase_t asio_server_connection::handle_headers() { std::istream request_stream(&m_request_buf); request_stream.imbue(std::locale::classic()); @@ -367,8 +525,9 @@ void connection::handle_headers() { m_request.reply(status_codes::BadRequest); m_close = true; - do_response(true); - return; + (will_erase_from_parent_t)do_bad_response(); + (will_deref_t)deref(); + return will_deref_and_erase_t{}; } } @@ -388,9 +547,9 @@ void connection::handle_headers() m_request._get_impl()->_prepare_to_receive_data(); if (m_chunked) { - async_read_until(); - dispatch_request_to_listener(); - return; + ++m_refs; + (will_deref_t)async_handle_chunked_header(); + return dispatch_request_to_listener(); } if (!m_request.headers().match(header_names::content_length, m_read_size)) @@ -405,17 +564,22 @@ void connection::handle_headers() else // need to read the sent data { m_read = 0; - async_read_until_buffersize(std::min(ChunkSize, m_read_size), boost::bind(&connection::handle_body, this, placeholders::error)); + ++m_refs; + async_read_until_buffersize(std::min(ChunkSize, m_read_size), [this](const boost::system::error_code& ec, size_t) + { + (will_deref_t)this->handle_body(ec); + }); } - dispatch_request_to_listener(); + return dispatch_request_to_listener(); } -void connection::handle_chunked_header(const boost::system::error_code& ec) +will_deref_t asio_server_connection::handle_chunked_header(const boost::system::error_code& ec) { if (ec) { m_request._get_impl()->_complete(0, std::make_exception_ptr(http_exception(ec.value()))); + return deref(); } else { @@ -426,22 +590,32 @@ void connection::handle_chunked_header(const boost::system::error_code& ec) m_request_buf.consume(CRLF.size()); m_read += len; if (len == 0) + { m_request._get_impl()->_complete(m_read); + return deref(); + } else - async_read_until_buffersize(len + 2, boost::bind(&connection::handle_chunked_body, this, boost::asio::placeholders::error, len)); + { + async_read_until_buffersize(len + 2, [this, len](const boost::system::error_code& ec, size_t) + { + (will_deref_t)this->handle_chunked_body(ec, len); + }); + return will_deref_t{}; + } } } -void connection::handle_chunked_body(const boost::system::error_code& ec, int toWrite) +will_deref_t asio_server_connection::handle_chunked_body(const boost::system::error_code& ec, int toWrite) { if (ec) { m_request._get_impl()->_complete(0, std::make_exception_ptr(http_exception(ec.value()))); + return deref(); } else { auto writebuf = m_request._get_impl()->outstream().streambuf(); - writebuf.putn_nocopy(buffer_cast(m_request_buf.data()), toWrite).then([=](pplx::task writeChunkTask) + writebuf.putn_nocopy(buffer_cast(m_request_buf.data()), toWrite).then([=](pplx::task writeChunkTask) -> will_deref_t { try { @@ -450,26 +624,28 @@ void connection::handle_chunked_body(const boost::system::error_code& ec, int to catch (...) { m_request._get_impl()->_complete(0, std::current_exception()); - return; + return deref(); } m_request_buf.consume(2 + toWrite); - async_read_until(); + return async_handle_chunked_header(); }); + return will_deref_t{}; } } -void connection::handle_body(const boost::system::error_code& ec) +will_deref_t asio_server_connection::handle_body(const boost::system::error_code& ec) { // read body if (ec) { m_request._get_impl()->_complete(0, std::make_exception_ptr(http_exception(ec.value()))); + return deref(); } else if (m_read < m_read_size) // there is more to read { auto writebuf = m_request._get_impl()->outstream().streambuf(); - writebuf.putn_nocopy(boost::asio::buffer_cast(m_request_buf.data()), std::min(m_request_buf.size(), m_read_size - m_read)).then([=](pplx::task writtenSizeTask) + writebuf.putn_nocopy(boost::asio::buffer_cast(m_request_buf.data()), std::min(m_request_buf.size(), m_read_size - m_read)).then([=](pplx::task writtenSizeTask) -> will_deref_t { size_t writtenSize = 0; try @@ -479,20 +655,27 @@ void connection::handle_body(const boost::system::error_code& ec) catch (...) { m_request._get_impl()->_complete(0, std::current_exception()); - return; + return deref(); } m_read += writtenSize; m_request_buf.consume(writtenSize); - async_read_until_buffersize(std::min(ChunkSize, m_read_size - m_read), boost::bind(&connection::handle_body, this, placeholders::error)); + + async_read_until_buffersize(std::min(ChunkSize, m_read_size - m_read), [this](const boost::system::error_code& ec, size_t) + { + (will_deref_t) this->handle_body(ec); + }); + return will_deref_t{}; }); + return will_deref_t{}; } else // have read request body { m_request._get_impl()->_complete(m_read); + return deref(); } } -void connection::async_write(ResponseFuncPtr response_func_ptr, const http_response &response) +will_deref_and_erase_t asio_server_connection::async_write(WriteFunc response_func_ptr, const http_response &response) { if (m_ssl_stream) { @@ -508,48 +691,51 @@ void connection::async_write(ResponseFuncPtr response_func_ptr, const http_respo (this->*response_func_ptr)(response, ec); }); } + return will_deref_and_erase_t{}; } -template -void connection::async_read(CompletionCondition &&condition, Handler &&read_handler) +will_deref_t asio_server_connection::async_handle_chunked_header() { if (m_ssl_stream) { - boost::asio::async_read(*m_ssl_stream, m_request_buf, std::forward(condition), std::forward(read_handler)); + boost::asio::async_read_until(*m_ssl_stream, m_request_buf, CRLF, [this](const boost::system::error_code& ec, size_t) + { + (will_deref_t)this->handle_chunked_header(ec); + }); } else { - boost::asio::async_read(*m_socket, m_request_buf, std::forward(condition), std::forward(read_handler)); + boost::asio::async_read_until(*m_socket, m_request_buf, CRLF, [this](const boost::system::error_code& ec, size_t) + { + (will_deref_t)this->handle_chunked_header(ec); + }); } + return will_deref_t{}; } -void connection::async_read_until() +template +void asio_server_connection::async_read_until_buffersize(size_t size, const ReadHandler &handler) { - if (m_ssl_stream) - { - boost::asio::async_read_until(*m_ssl_stream, m_request_buf, CRLF, boost::bind(&connection::handle_chunked_header, this, placeholders::error)); - } - else + // The condition is such that after completing the async_read below, m_request_buf will contain at least `size` bytes. + auto condition = transfer_at_least(0); + + auto bufsize = m_request_buf.size(); + if (size > bufsize) { - boost::asio::async_read_until(*m_socket, m_request_buf, CRLF, boost::bind(&connection::handle_chunked_header, this, placeholders::error)); + condition = transfer_at_least(size - bufsize); } -} -template -void connection::async_read_until_buffersize(size_t size, const ReadHandler &handler) -{ - auto bufsize = m_request_buf.size(); - if (bufsize >= size) + if (m_ssl_stream) { - async_read(transfer_at_least(0), handler); + boost::asio::async_read(*m_ssl_stream, m_request_buf, condition, handler); } else { - async_read(transfer_at_least(size - bufsize), handler); + boost::asio::async_read(*m_socket, m_request_buf, condition, handler); } } -void connection::dispatch_request_to_listener() +will_deref_and_erase_t asio_server_connection::dispatch_request_to_listener() { // locate the listener: web::http::experimental::listener::details::http_listener_impl* pListener = nullptr; @@ -577,77 +763,50 @@ void connection::dispatch_request_to_listener() if (pListener == nullptr) { m_request.reply(status_codes::NotFound); - do_response(false); + (will_erase_from_parent_t)do_response(); + (will_deref_t)deref(); + return will_deref_and_erase_t{}; } - else + + m_request._set_listener_path(pListener->uri().path()); + (will_erase_from_parent_t)do_response(); + + // Look up the lock for the http_listener. + pplx::extensibility::reader_writer_lock_t *pListenerLock; { - m_request._set_listener_path(pListener->uri().path()); - do_response(false); + pplx::extensibility::reader_writer_lock_t::scoped_lock_read lock(m_p_server->m_listeners_lock); - // Look up the lock for the http_listener. - pplx::extensibility::reader_writer_lock_t *pListenerLock; + // It is possible the listener could have unregistered. + if(m_p_server->m_registered_listeners.find(pListener) == m_p_server->m_registered_listeners.end()) { - pplx::extensibility::reader_writer_lock_t::scoped_lock_read lock(m_p_server->m_listeners_lock); + m_request.reply(status_codes::NotFound); - // It is possible the listener could have unregistered. - if(m_p_server->m_registered_listeners.find(pListener) == m_p_server->m_registered_listeners.end()) - { - m_request.reply(status_codes::NotFound); - return; - } - pListenerLock = m_p_server->m_registered_listeners[pListener].get(); - - // We need to acquire the listener's lock before releasing the registered listeners lock. - // But we don't need to hold the registered listeners lock when calling into the user's code. - pListenerLock->lock_read(); + (will_deref_t)deref(); + return will_deref_and_erase_t{}; } + pListenerLock = m_p_server->m_registered_listeners[pListener].get(); - try - { - pListener->handle_request(m_request); - pListenerLock->unlock(); - } - catch(...) - { - pListenerLock->unlock(); - m_request._reply_if_not_already(status_codes::InternalError); - } + // We need to acquire the listener's lock before releasing the registered listeners lock. + // But we don't need to hold the registered listeners lock when calling into the user's code. + pListenerLock->lock_read(); } - - if (--m_refs == 0) delete this; -} -void connection::do_response(bool bad_request) -{ - ++m_refs; - m_request.get_response().then([=](pplx::task r_task) + try { - http::http_response response; - try - { - response = r_task.get(); - } - catch(...) - { - response = http::http_response(status_codes::InternalError); - } + pListener->handle_request(m_request); + pListenerLock->unlock(); + } + catch(...) + { + pListenerLock->unlock(); + m_request._reply_if_not_already(status_codes::InternalError); + } - // before sending response, the full incoming message need to be processed. - if (bad_request) - { - async_process_response(response); - } - else - { - m_request.content_ready().then([=](pplx::task) - { - async_process_response(response); - }); - } - }); + (will_deref_t)deref(); + return will_deref_and_erase_t{}; } -void connection::async_process_response(http_response response) +void asio_server_connection::serialize_headers(http_response response) { m_response_buf.consume(m_response_buf.size()); // clear the buffer std::ostream os(&m_response_buf); @@ -688,20 +847,18 @@ void connection::async_process_response(http_response response) os << utility::conversions::to_utf8string(header.first) << ": " << utility::conversions::to_utf8string(header.second) << CRLF; } os << CRLF; - - async_write(&connection::handle_headers_written, response); } -void connection::cancel_sending_response_with_error(const http_response &response, const std::exception_ptr &eptr) +will_deref_and_erase_t asio_server_connection::cancel_sending_response_with_error(const http_response &response, const std::exception_ptr &eptr) { auto * context = static_cast(response._get_server_context()); context->m_response_completed.set_exception(eptr); // always terminate the connection since error happens - finish_request_response(); + return finish_request_response(); } -void connection::handle_write_chunked_response(const http_response &response, const boost::system::error_code& ec) +will_deref_and_erase_t asio_server_connection::handle_write_chunked_response(const http_response &response, const boost::system::error_code& ec) { if (ec) { @@ -715,24 +872,31 @@ void connection::handle_write_chunked_response(const http_response &response, co } auto membuf = m_response_buf.prepare(ChunkSize + http::details::chunked_encoding::additional_encoding_space); - readbuf.getn(buffer_cast(membuf) + http::details::chunked_encoding::data_offset, ChunkSize).then([=](pplx::task actualSizeTask) + readbuf.getn(buffer_cast(membuf) + http::details::chunked_encoding::data_offset, ChunkSize).then([=](pplx::task actualSizeTask) -> will_deref_and_erase_t { size_t actualSize = 0; try { actualSize = actualSizeTask.get(); - } catch (...) + } + catch (...) { return cancel_sending_response_with_error(response, std::current_exception()); } - size_t offset = http::details::chunked_encoding::add_chunked_delimiters(buffer_cast(membuf), ChunkSize+http::details::chunked_encoding::additional_encoding_space, actualSize); + size_t offset = http::details::chunked_encoding::add_chunked_delimiters(buffer_cast(membuf), ChunkSize + http::details::chunked_encoding::additional_encoding_space, actualSize); m_response_buf.commit(actualSize + http::details::chunked_encoding::additional_encoding_space); m_response_buf.consume(offset); - async_write(actualSize == 0 ? &connection::handle_response_written : &connection::handle_write_chunked_response, response); + if (actualSize == 0) + return async_write(&asio_server_connection::handle_response_written, response); + else + return async_write(&asio_server_connection::handle_write_chunked_response, response); }); + return will_deref_and_erase_t{}; } -void connection::handle_write_large_response(const http_response &response, const boost::system::error_code& ec) +will_deref_and_erase_t asio_server_connection::handle_write_large_response( + const http_response &response, + const boost::system::error_code& ec) { if (ec || m_write == m_write_size) return handle_response_written(response, ec); @@ -741,7 +905,7 @@ void connection::handle_write_large_response(const http_response &response, cons if (readbuf.is_eof()) return cancel_sending_response_with_error(response, std::make_exception_ptr(http_exception("Response stream close early!"))); size_t readBytes = std::min(ChunkSize, m_write_size - m_write); - readbuf.getn(buffer_cast(m_response_buf.prepare(readBytes)), readBytes).then([=](pplx::task actualSizeTask) + readbuf.getn(buffer_cast(m_response_buf.prepare(readBytes)), readBytes).then([=](pplx::task actualSizeTask) -> will_deref_and_erase_t { size_t actualSize = 0; try @@ -753,11 +917,12 @@ void connection::handle_write_large_response(const http_response &response, cons } m_write += actualSize; m_response_buf.commit(actualSize); - async_write(&connection::handle_write_large_response, response); + return async_write(&asio_server_connection::handle_write_large_response, response); }); + return will_deref_and_erase_t{}; } -void connection::handle_headers_written(const http_response &response, const boost::system::error_code& ec) +will_deref_and_erase_t asio_server_connection::handle_headers_written(const http_response &response, const boost::system::error_code& ec) { if (ec) { @@ -766,13 +931,15 @@ void connection::handle_headers_written(const http_response &response, const boo else { if (m_chunked) - handle_write_chunked_response(response, ec); + return handle_write_chunked_response(response, ec); else - handle_write_large_response(response, ec); + return handle_write_large_response(response, ec); } } -void connection::handle_response_written(const http_response &response, const boost::system::error_code& ec) +will_deref_and_erase_t asio_server_connection::handle_response_written( + const http_response &response, + const boost::system::error_code& ec) { auto * context = static_cast(response._get_server_context()); if (ec) @@ -784,16 +951,16 @@ void connection::handle_response_written(const http_response &response, const bo context->m_response_completed.set(); if (!m_close) { - start_request_response(); + return start_request_response(); } else { - finish_request_response(); + return finish_request_response(); } } } -void connection::finish_request_response() +will_deref_and_erase_t asio_server_connection::finish_request_response() { // kill the connection { @@ -804,9 +971,12 @@ void connection::finish_request_response() m_p_parent->m_all_connections_complete.set(); } } - + close(); - if (--m_refs == 0) delete this; + (will_deref_t)deref(); + + // m_connections.erase has been called above. + return will_deref_and_erase_t{}; } void hostport_listener::stop() From d0ef0b78de4a2a1ace39648c5645def9086587f3 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 19 Apr 2017 13:59:16 -0700 Subject: [PATCH 052/438] Fix regressions in PR #251 --- Release/src/utilities/asyncrt_utils.cpp | 75 +++++++++---------------- 1 file changed, 28 insertions(+), 47 deletions(-) diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index bf586df5a6..0e62bdeea4 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -25,12 +25,6 @@ #endif #endif -// Could use C++ standard library if not __GLIBCXX__, -// For testing purposes we just the handwritten on all platforms. -#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS) -#include -#endif - using namespace web; using namespace utility; using namespace utility::conversions; @@ -346,10 +340,6 @@ inline size_t count_utf8_to_utf16(const std::string& s) utf16string __cdecl conversions::utf8_to_utf16(const std::string &s) { -#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS) - std::wstring_convert, utf16char> conversion; - return conversion.from_bytes(s); -#else // Save repeated heap allocations, use the length of resulting sequence. const size_t srcSize = s.size(); const std::string::value_type* const srcData = &s[0]; @@ -391,7 +381,7 @@ utf16string __cdecl conversions::utf8_to_utf16(const std::string &s) { const char c2{ srcData[++index] }; const char c3{ srcData[++index] }; - destData[destIndex++] = ((src & LOW_4BITS) << 12) | ((c2 & LOW_6BITS) << 6) | (c3 & LOW_6BITS); + destData[destIndex++] = static_cast(((src & LOW_4BITS) << 12) | ((c2 & LOW_6BITS) << 6) | (c3 & LOW_6BITS)); } break; case 0xD0: // 2 byte character, 0x80 to 0x7FF @@ -406,7 +396,6 @@ utf16string __cdecl conversions::utf8_to_utf16(const std::string &s) } } return dest; -#endif } @@ -453,10 +442,6 @@ inline size_t count_utf16_to_utf8(const utf16string &w) std::string __cdecl conversions::utf16_to_utf8(const utf16string &w) { - #if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS) - std::wstring_convert, utf16char> conversion; - return conversion.to_bytes(w); - #else const size_t srcSize = w.size(); const utf16string::value_type* const srcData = &w[0]; std::string dest(count_utf16_to_utf8(w), '\0'); @@ -465,7 +450,7 @@ std::string __cdecl conversions::utf16_to_utf8(const utf16string &w) for (size_t index = 0; index < srcSize; ++index) { - const utf16string::value_type src{ srcData[index] }; + const utf16string::value_type src = srcData[index]; if (src <= 0x7FF) { if (src <= 0x7F) // single byte character @@ -478,41 +463,37 @@ std::string __cdecl conversions::utf16_to_utf8(const utf16string &w) destData[destIndex++] = static_cast(char((src & LOW_6BITS) | BIT8)); // trailing 6 bits } } - else + // Check for high surrogate. + else if (src >= H_SURROGATE_START && src <= H_SURROGATE_END) { - // Check for high surrogate. - if (src >= H_SURROGATE_START && src <= H_SURROGATE_END) - { - const auto highSurrogate{ src }; - const auto lowSurrogate{ srcData[++index] }; - - // To get from surrogate pair to Unicode code point: - // - subract 0xD800 from high surrogate, this forms top ten bits - // - subract 0xDC00 from low surrogate, this forms low ten bits - // - add 0x10000 - // Leaves a code point in U+10000 to U+10FFFF range. - uint32_t codePoint = highSurrogate - H_SURROGATE_START; - codePoint <<= 10; - codePoint |= lowSurrogate - L_SURROGATE_START; - codePoint += SURROGATE_PAIR_START; - - // 4 bytes need using 21 bits - destData[destIndex++] = static_cast((codePoint >> 18) | 0xF0); // leading 3 bits - destData[destIndex++] = static_cast(((codePoint >> 12) & LOW_6BITS) | BIT8); // next 6 bits - destData[destIndex++] = static_cast(((codePoint >> 6) & LOW_6BITS) | BIT8); // next 6 bits - destData[destIndex++] = static_cast((codePoint & LOW_6BITS) | BIT8); // trailing 6 bits - } - else // 3 bytes needed (16 bits used) - { - destData[destIndex++] = static_cast((src >> 12) | 0xE0); // leading 4 bits - destData[destIndex++] = static_cast(((src >> 6) & LOW_6BITS) | BIT8); // middle 6 bits - destData[destIndex++] = static_cast((src & LOW_6BITS) | BIT8); // trailing 6 bits - } + const auto highSurrogate = src; + const auto lowSurrogate = srcData[++index]; + + // To get from surrogate pair to Unicode code point: + // - subract 0xD800 from high surrogate, this forms top ten bits + // - subract 0xDC00 from low surrogate, this forms low ten bits + // - add 0x10000 + // Leaves a code point in U+10000 to U+10FFFF range. + uint32_t codePoint = highSurrogate - H_SURROGATE_START; + codePoint <<= 10; + codePoint |= lowSurrogate - L_SURROGATE_START; + codePoint += SURROGATE_PAIR_START; + + // 4 bytes need using 21 bits + destData[destIndex++] = static_cast((codePoint >> 18) | 0xF0); // leading 3 bits + destData[destIndex++] = static_cast(((codePoint >> 12) & LOW_6BITS) | BIT8); // next 6 bits + destData[destIndex++] = static_cast(((codePoint >> 6) & LOW_6BITS) | BIT8); // next 6 bits + destData[destIndex++] = static_cast((codePoint & LOW_6BITS) | BIT8); // trailing 6 bits + } + else // 3 bytes needed (16 bits used) + { + destData[destIndex++] = static_cast((src >> 12) | 0xE0); // leading 4 bits + destData[destIndex++] = static_cast(((src >> 6) & LOW_6BITS) | BIT8); // middle 6 bits + destData[destIndex++] = static_cast((src & LOW_6BITS) | BIT8); // trailing 6 bits } } return dest; - #endif } utf16string __cdecl conversions::usascii_to_utf16(const std::string &s) From 256fe993fb95033c7328e399f7b77141fd8e6f94 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 19 Apr 2017 16:27:52 -0700 Subject: [PATCH 053/438] Refactor http_server_httpsys/http_server_asio to be internal-only. --- .../cpprest/details/http_server_asio.h | 149 -------- Release/src/CMakeLists.txt | 5 +- Release/src/build/win32.vcxitems | 2 +- Release/src/build/win32.vcxitems.filters | 2 +- Release/src/http/listener/http_server_api.cpp | 5 +- .../src/http/listener/http_server_asio.cpp | 328 +++++++++++++----- .../src/http/listener/http_server_httpsys.cpp | 7 + .../http/listener}/http_server_httpsys.h | 0 Release/src/http/listener/http_server_impl.h | 15 + Release/src/pch/stdafx.h | 10 +- 10 files changed, 271 insertions(+), 252 deletions(-) delete mode 100644 Release/include/cpprest/details/http_server_asio.h rename Release/{include/cpprest/details => src/http/listener}/http_server_httpsys.h (100%) create mode 100644 Release/src/http/listener/http_server_impl.h diff --git a/Release/include/cpprest/details/http_server_asio.h b/Release/include/cpprest/details/http_server_asio.h deleted file mode 100644 index 13c4d7e51a..0000000000 --- a/Release/include/cpprest/details/http_server_asio.h +++ /dev/null @@ -1,149 +0,0 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -****/ - -#pragma once - -#include -#include "pplx/threadpool.h" -#include "cpprest/details/http_server.h" -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#pragma clang diagnostic ignored "-Winfinite-recursion" -#endif -#include -#include -#if defined(__clang__) -#pragma clang diagnostic pop -#endif -#include -#include - -namespace web -{ -namespace http -{ -namespace experimental -{ -namespace listener -{ - -class http_linux_server; - -namespace details -{ - -struct linux_request_context : web::http::details::_http_server_context -{ - linux_request_context(){} - - pplx::task_completion_event m_response_completed; - -private: - linux_request_context(const linux_request_context&); - linux_request_context& operator=(const linux_request_context&); -}; - -class asio_server_connection; - -class hostport_listener -{ -private: - friend class asio_server_connection; - - std::unique_ptr m_acceptor; - std::map m_listeners; - pplx::extensibility::reader_writer_lock_t m_listeners_lock; - - std::mutex m_connections_lock; - pplx::extensibility::event_t m_all_connections_complete; - std::set m_connections; - - http_linux_server* m_p_server; - - std::string m_host; - std::string m_port; - - bool m_is_https; - const std::function& m_ssl_context_callback; - -public: - hostport_listener(http_linux_server* server, const std::string& hostport, bool is_https, const http_listener_config& config) - : m_acceptor() - , m_listeners() - , m_listeners_lock() - , m_connections_lock() - , m_connections() - , m_p_server(server) - , m_is_https(is_https) - , m_ssl_context_callback(config.get_ssl_context_callback()) - { - m_all_connections_complete.set(); - - std::istringstream hostport_in(hostport); - hostport_in.imbue(std::locale::classic()); - - std::getline(hostport_in, m_host, ':'); - std::getline(hostport_in, m_port); - } - - ~hostport_listener() - { - stop(); - } - - void start(); - void stop(); - - void add_listener(const std::string& path, web::http::experimental::listener::details::http_listener_impl* listener); - void remove_listener(const std::string& path, web::http::experimental::listener::details::http_listener_impl* listener); - -private: - void on_accept(boost::asio::ip::tcp::socket* socket, const boost::system::error_code& ec); - -}; - -} - -struct iequal_to -{ - bool operator()(const std::string& left, const std::string& right) const - { - return boost::ilexicographical_compare(left, right); - } -}; - -class http_linux_server : public web::http::experimental::details::http_server -{ -private: - friend class http::experimental::listener::details::asio_server_connection; - - pplx::extensibility::reader_writer_lock_t m_listeners_lock; - std::map, iequal_to> m_listeners; - std::unordered_map> m_registered_listeners; - bool m_started; - -public: - http_linux_server() - : m_listeners_lock() - , m_listeners() - , m_started(false) - {} - - ~http_linux_server() - { - stop(); - } - - virtual pplx::task start(); - virtual pplx::task stop(); - - virtual pplx::task register_listener(web::http::experimental::listener::details::http_listener_impl* listener); - virtual pplx::task unregister_listener(web::http::experimental::listener::details::http_listener_impl* listener); - - pplx::task respond(http::http_response response); -}; - -}}}} diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index f166fc76d6..7385a8d877 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -22,6 +22,7 @@ set(SOURCES http/listener/http_listener.cpp http/listener/http_listener_msg.cpp http/listener/http_server_api.cpp + http/listener/http_server_impl.h http/oauth/oauth1.cpp http/oauth/oauth2.cpp json/json.cpp @@ -101,7 +102,9 @@ endif() if(CPPREST_HTTP_LISTENER_IMPL STREQUAL "asio") list(APPEND SOURCES http/listener/http_server_asio.cpp) elseif(CPPREST_HTTP_LISTENER_IMPL STREQUAL "httpsys") - list(APPEND SOURCES http/listener/http_server_httpsys.cpp) + list(APPEND SOURCES + http/listener/http_server_httpsys.cpp + http/listener/http_server_httpsys.h) endif() if(MSVC) diff --git a/Release/src/build/win32.vcxitems b/Release/src/build/win32.vcxitems index 0d9e515317..216b00fca5 100644 --- a/Release/src/build/win32.vcxitems +++ b/Release/src/build/win32.vcxitems @@ -27,7 +27,7 @@ - + \ No newline at end of file diff --git a/Release/src/build/win32.vcxitems.filters b/Release/src/build/win32.vcxitems.filters index f32d09f1d2..0a8e8e865a 100644 --- a/Release/src/build/win32.vcxitems.filters +++ b/Release/src/build/win32.vcxitems.filters @@ -26,7 +26,7 @@ - + Header Files diff --git a/Release/src/http/listener/http_server_api.cpp b/Release/src/http/listener/http_server_api.cpp index 3e64a2dfcf..05a4cdc1f2 100644 --- a/Release/src/http/listener/http_server_api.cpp +++ b/Release/src/http/listener/http_server_api.cpp @@ -10,6 +10,7 @@ ****/ #include "stdafx.h" +#include "http_server_impl.h" #if !defined(_WIN32) || (_WIN32_WINNT >= _WIN32_WINNT_VISTA && !defined(__cplusplus_winrt)) @@ -73,9 +74,9 @@ pplx::task http_server_api::register_listener(_In_ web::http::experimental if(s_server_api == nullptr) { #if defined(_WIN32) && !defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) - std::unique_ptr server_api(new http_windows_server()); + auto server_api = make_http_httpsys_server(); #else - std::unique_ptr server_api(new http_linux_server()); + auto server_api = make_http_asio_server(); #endif http_server_api::unsafe_register_server_api(std::move(server_api)); diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 76645c1054..30d8654f6d 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -14,18 +14,25 @@ */ #include "stdafx.h" #include +#include #include + #if defined(__clang__) #pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wcast-align" +#pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Winfinite-recursion" #endif +#include +#include #if defined(__clang__) #pragma clang diagnostic pop #endif #include "cpprest/details/http_server_asio.h" #include "cpprest/asyncrt_utils.h" +#include "pplx/threadpool.h" #include "../common/internal_http_helpers.h" +#include "http_server_impl.h" #ifdef __ANDROID__ using utility::conversions::details::to_string; @@ -39,15 +46,162 @@ using namespace boost::asio::ip; #define CRLF std::string("\r\n") #define CRLFCRLF std::string("\r\n\r\n") -namespace web -{ -namespace http -{ -namespace experimental +namespace listener = web::http::experimental::listener; +namespace chunked_encoding = web::http::details::chunked_encoding; + +using web::uri; +using web::http::http_request; +using web::http::http_response; +using web::http::methods; +using web::http::status_codes; +using web::http::header_names; +using web::http::http_exception; +using web::http::experimental::listener::details::http_listener_impl; +using web::http::experimental::listener::http_listener_config; + +using utility::details::make_unique; + +namespace { -namespace listener + class hostport_listener; + class http_linux_server; + class asio_server_connection; +} + +namespace { -namespace details + struct iequal_to + { + bool operator()(const std::string& left, const std::string& right) const + { + return boost::ilexicographical_compare(left, right); + } + }; + + class http_linux_server : public web::http::experimental::details::http_server + { + private: + friend class asio_server_connection; + + pplx::extensibility::reader_writer_lock_t m_listeners_lock; + std::map, iequal_to> m_listeners; + std::unordered_map> m_registered_listeners; + bool m_started; + + public: + http_linux_server() + : m_listeners_lock() + , m_listeners() + , m_started(false) + {} + + ~http_linux_server() + { + stop(); + } + + virtual pplx::task start(); + virtual pplx::task stop(); + + virtual pplx::task register_listener(http_listener_impl* listener); + virtual pplx::task unregister_listener(http_listener_impl* listener); + + pplx::task respond(http_response response); + }; + + struct linux_request_context : web::http::details::_http_server_context + { + linux_request_context() {} + + pplx::task_completion_event m_response_completed; + + private: + linux_request_context(const linux_request_context&) = delete; + linux_request_context& operator=(const linux_request_context&) = delete; + }; + + class hostport_listener + { + private: + std::unique_ptr m_acceptor; + std::map m_listeners; + pplx::extensibility::reader_writer_lock_t m_listeners_lock; + + std::mutex m_connections_lock; + pplx::extensibility::event_t m_all_connections_complete; + std::set m_connections; + + http_linux_server* m_p_server; + + std::string m_host; + std::string m_port; + + bool m_is_https; + const std::function& m_ssl_context_callback; + + public: + hostport_listener(http_linux_server* server, const std::string& hostport, bool is_https, const http_listener_config& config) + : m_acceptor() + , m_listeners() + , m_listeners_lock() + , m_connections_lock() + , m_connections() + , m_p_server(server) + , m_is_https(is_https) + , m_ssl_context_callback(config.get_ssl_context_callback()) + { + m_all_connections_complete.set(); + + std::istringstream hostport_in(hostport); + hostport_in.imbue(std::locale::classic()); + + std::getline(hostport_in, m_host, ':'); + std::getline(hostport_in, m_port); + } + + ~hostport_listener() + { + stop(); + } + + void start(); + void stop(); + + void add_listener(const std::string& path, http_listener_impl* listener); + void remove_listener(const std::string& path, http_listener_impl* listener); + + void internal_erase_connection(asio_server_connection*); + + http_listener_impl* find_listener(uri const& u) + { + auto path_segments = uri::split_path(uri::decode(u.path())); + for (auto i = static_cast(path_segments.size()); i >= 0; --i) + { + std::string path = ""; + for (size_t j = 0; j < static_cast(i); ++j) + { + path += "/" + utility::conversions::to_utf8string(path_segments[j]); + } + path += "/"; + + pplx::extensibility::scoped_read_lock_t lock(m_listeners_lock); + auto it = m_listeners.find(path); + if (it != m_listeners.end()) + { + return it->second; + } + } + return nullptr; + } + + private: + void on_accept(boost::asio::ip::tcp::socket* socket, const boost::system::error_code& ec); + + }; + +} + +namespace { /// This class replaces the regex "\r\n\r\n|[\x00-\x1F]|[\x80-\xFF]" // It was added due to issues with regex on Android, however since @@ -190,12 +344,12 @@ class asio_server_connection { if (is_https) { - m_ssl_context = utility::details::make_unique(boost::asio::ssl::context::sslv23); + m_ssl_context = make_unique(boost::asio::ssl::context::sslv23); if (ssl_context_callback) { ssl_context_callback(*m_ssl_context); } - m_ssl_stream = utility::details::make_unique(*m_socket, *m_ssl_context); + m_ssl_stream = make_unique(*m_socket, *m_ssl_context); m_ssl_stream->async_handshake(boost::asio::ssl::stream_base::server, [this](const boost::system::error_code&) { @@ -227,22 +381,22 @@ class asio_server_connection will_erase_from_parent_t do_response() { ++m_refs; - m_request.get_response().then([=](pplx::task r_task) + m_request.get_response().then([=](pplx::task r_task) { - http::http_response response; + http_response response; try { response = r_task.get(); } catch (...) { - response = http::http_response(status_codes::InternalError); + response = http_response(status_codes::InternalError); } serialize_headers(response); // before sending response, the full incoming message need to be processed. - return m_request.content_ready().then([=](pplx::task) + return m_request.content_ready().then([=](pplx::task) { (will_deref_and_erase_t)this->async_write(&asio_server_connection::handle_headers_written, response); }); @@ -252,16 +406,16 @@ class asio_server_connection will_erase_from_parent_t do_bad_response() { ++m_refs; - m_request.get_response().then([=](pplx::task r_task) + m_request.get_response().then([=](pplx::task r_task) { - http::http_response response; + http_response response; try { response = r_task.get(); } catch (...) { - response = http::http_response(status_codes::InternalError); + response = http_response(status_codes::InternalError); } // before sending response, the full incoming message need to be processed. @@ -293,28 +447,29 @@ class asio_server_connection } }; -}}}}} +} namespace boost { namespace asio { -template <> struct is_match_condition : public boost::true_type {}; +template <> struct is_match_condition : public boost::true_type {}; }} -namespace web -{ -namespace http -{ -namespace experimental -{ -namespace listener +namespace { const size_t ChunkSize = 4 * 1024; -namespace details +void hostport_listener::internal_erase_connection(asio_server_connection* conn) { + std::lock_guard lock(m_connections_lock); + m_connections.erase(conn); + if (m_connections.empty()) + { + m_all_connections_complete.set(); + } +} void hostport_listener::start() { @@ -328,7 +483,10 @@ void hostport_listener::start() m_acceptor->set_option(tcp::acceptor::reuse_address(true)); auto socket = new ip::tcp::socket(service); - m_acceptor->async_accept(*socket, boost::bind(&hostport_listener::on_accept, this, socket, placeholders::error)); + m_acceptor->async_accept(*socket, [this, socket](const boost::system::error_code& ec) + { + this->on_accept(socket, ec); + }); } void asio_server_connection::close() @@ -386,14 +544,17 @@ void hostport_listener::on_accept(ip::tcp::socket* socket, const boost::system:: { // spin off another async accept auto newSocket = new ip::tcp::socket(crossplat::threadpool::shared_instance().service()); - m_acceptor->async_accept(*newSocket, boost::bind(&hostport_listener::on_accept, this, newSocket, placeholders::error)); + m_acceptor->async_accept(*newSocket, [this, newSocket](const boost::system::error_code& ec) + { + this->on_accept(newSocket, ec); + }); } } } will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::system::error_code& ec) { - m_request = http_request::_create_request(std::unique_ptr(new linux_request_context())); + m_request = http_request::_create_request(make_unique()); if (ec) { // client closed connection @@ -433,14 +594,14 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys } #endif - if (boost::iequals(http_verb, http::methods::GET)) http_verb = http::methods::GET; - else if (boost::iequals(http_verb, http::methods::POST)) http_verb = http::methods::POST; - else if (boost::iequals(http_verb, http::methods::PUT)) http_verb = http::methods::PUT; - else if (boost::iequals(http_verb, http::methods::DEL)) http_verb = http::methods::DEL; - else if (boost::iequals(http_verb, http::methods::HEAD)) http_verb = http::methods::HEAD; - else if (boost::iequals(http_verb, http::methods::TRCE)) http_verb = http::methods::TRCE; - else if (boost::iequals(http_verb, http::methods::CONNECT)) http_verb = http::methods::CONNECT; - else if (boost::iequals(http_verb, http::methods::OPTIONS)) http_verb = http::methods::OPTIONS; + if (boost::iequals(http_verb, methods::GET)) http_verb = methods::GET; + else if (boost::iequals(http_verb, methods::POST)) http_verb = methods::POST; + else if (boost::iequals(http_verb, methods::PUT)) http_verb = methods::PUT; + else if (boost::iequals(http_verb, methods::DEL)) http_verb = methods::DEL; + else if (boost::iequals(http_verb, methods::HEAD)) http_verb = methods::HEAD; + else if (boost::iequals(http_verb, methods::TRCE)) http_verb = methods::TRCE; + else if (boost::iequals(http_verb, methods::CONNECT)) http_verb = methods::CONNECT; + else if (boost::iequals(http_verb, methods::OPTIONS)) http_verb = methods::OPTIONS; // Check to see if there is not allowed character on the input if (!web::http::details::validate_method(http_verb)) @@ -473,7 +634,7 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys { m_request.set_request_uri(utility::conversions::to_string_t(http_path_and_version.substr(1, http_path_and_version.size() - VersionPortionSize - 1))); } - catch(const uri_exception &e) + catch(const web::uri_exception &e) { m_request.reply(status_codes::BadRequest, e.what()); m_close = true; @@ -509,12 +670,12 @@ will_deref_and_erase_t asio_server_connection::handle_headers() { auto name = utility::conversions::to_string_t(header.substr(0, colon)); auto value = utility::conversions::to_string_t(header.substr(colon + 1, header.length() - (colon + 1))); // also exclude '\r' - http::details::trim_whitespace(name); - http::details::trim_whitespace(value); + web::http::details::trim_whitespace(name); + web::http::details::trim_whitespace(value); if (boost::iequals(name, header_names::content_length)) { - headers[http::header_names::content_length] = value; + headers[header_names::content_length] = value; } else { @@ -735,30 +896,12 @@ void asio_server_connection::async_read_until_buffersize(size_t size, const Read } } + + will_deref_and_erase_t asio_server_connection::dispatch_request_to_listener() { // locate the listener: - web::http::experimental::listener::details::http_listener_impl* pListener = nullptr; - { - auto path_segments = uri::split_path(uri::decode(m_request.relative_uri().path())); - for (auto i = static_cast(path_segments.size()); i >= 0; --i) - { - std::string path = ""; - for (size_t j = 0; j < static_cast(i); ++j) - { - path += "/" + utility::conversions::to_utf8string(path_segments[j]); - } - path += "/"; - - pplx::extensibility::scoped_read_lock_t lock(m_p_parent->m_listeners_lock); - auto it = m_p_parent->m_listeners.find(path); - if (it != m_p_parent->m_listeners.end()) - { - pListener = it->second; - break; - } - } - } + http_listener_impl* pListener = m_p_parent->find_listener(m_request.relative_uri()); if (pListener == nullptr) { @@ -870,9 +1013,9 @@ will_deref_and_erase_t asio_server_connection::handle_write_chunked_response(con { return cancel_sending_response_with_error(response, std::make_exception_ptr(http_exception("Response stream close early!"))); } - auto membuf = m_response_buf.prepare(ChunkSize + http::details::chunked_encoding::additional_encoding_space); + auto membuf = m_response_buf.prepare(ChunkSize + chunked_encoding::additional_encoding_space); - readbuf.getn(buffer_cast(membuf) + http::details::chunked_encoding::data_offset, ChunkSize).then([=](pplx::task actualSizeTask) -> will_deref_and_erase_t + readbuf.getn(buffer_cast(membuf) + chunked_encoding::data_offset, ChunkSize).then([=](pplx::task actualSizeTask) -> will_deref_and_erase_t { size_t actualSize = 0; try @@ -883,8 +1026,8 @@ will_deref_and_erase_t asio_server_connection::handle_write_chunked_response(con { return cancel_sending_response_with_error(response, std::current_exception()); } - size_t offset = http::details::chunked_encoding::add_chunked_delimiters(buffer_cast(membuf), ChunkSize + http::details::chunked_encoding::additional_encoding_space, actualSize); - m_response_buf.commit(actualSize + http::details::chunked_encoding::additional_encoding_space); + size_t offset = chunked_encoding::add_chunked_delimiters(buffer_cast(membuf), ChunkSize + chunked_encoding::additional_encoding_space, actualSize); + m_response_buf.commit(actualSize + chunked_encoding::additional_encoding_space); m_response_buf.consume(offset); if (actualSize == 0) return async_write(&asio_server_connection::handle_response_written, response); @@ -963,19 +1106,12 @@ will_deref_and_erase_t asio_server_connection::handle_response_written( will_deref_and_erase_t asio_server_connection::finish_request_response() { // kill the connection - { - std::lock_guard lock(m_p_parent->m_connections_lock); - m_p_parent->m_connections.erase(this); - if (m_p_parent->m_connections.empty()) - { - m_p_parent->m_all_connections_complete.set(); - } - } + m_p_parent->internal_erase_connection(this); close(); (will_deref_t)deref(); - // m_connections.erase has been called above. + // internal_erase_connection has been called above. return will_deref_and_erase_t{}; } @@ -994,17 +1130,17 @@ void hostport_listener::stop() m_all_connections_complete.wait(); } -void hostport_listener::add_listener(const std::string& path, web::http::experimental::listener::details::http_listener_impl* listener) +void hostport_listener::add_listener(const std::string& path, http_listener_impl* listener) { pplx::extensibility::scoped_rw_lock_t lock(m_listeners_lock); if (m_is_https != (listener->uri().scheme() == U("https"))) throw std::invalid_argument("Error: http_listener can not simultaneously listen both http and https paths of one host"); - else if (!m_listeners.insert(std::map::value_type(path, listener)).second) + else if (!m_listeners.insert(std::map::value_type(path, listener)).second) throw std::invalid_argument("Error: http_listener is already registered for this path"); } -void hostport_listener::remove_listener(const std::string& path, web::http::experimental::listener::details::http_listener_impl*) +void hostport_listener::remove_listener(const std::string& path, http_listener_impl*) { pplx::extensibility::scoped_rw_lock_t lock(m_listeners_lock); @@ -1012,8 +1148,6 @@ void hostport_listener::remove_listener(const std::string& path, web::http::expe throw std::invalid_argument("Error: no http_listener found for this path"); } -} - pplx::task http_linux_server::start() { pplx::extensibility::reader_writer_lock_t::scoped_lock_read lock(m_listeners_lock); @@ -1054,7 +1188,7 @@ pplx::task http_linux_server::stop() return pplx::task_from_result(); } -std::pair canonical_parts(const http::uri& uri) +std::pair canonical_parts(const uri& uri) { std::string endpoint; endpoint += utility::conversions::to_utf8string(uri::decode(uri.host())); @@ -1071,7 +1205,7 @@ std::pair canonical_parts(const http::uri& uri) return std::make_pair(std::move(endpoint), std::move(path)); } -pplx::task http_linux_server::register_listener(details::http_listener_impl* listener) +pplx::task http_linux_server::register_listener(http_listener_impl* listener) { auto parts = canonical_parts(listener->uri()); auto hostport = parts.first; @@ -1087,13 +1221,13 @@ pplx::task http_linux_server::register_listener(details::http_listener_imp try { - m_registered_listeners[listener] = utility::details::make_unique(); + m_registered_listeners[listener] = make_unique(); auto found_hostport_listener = m_listeners.find(hostport); if (found_hostport_listener == m_listeners.end()) { found_hostport_listener = m_listeners.insert( - std::make_pair(hostport, utility::details::make_unique(this, hostport, is_https, listener->configuration()))).first; + std::make_pair(hostport, make_unique(this, hostport, is_https, listener->configuration()))).first; if (m_started) { @@ -1117,7 +1251,7 @@ pplx::task http_linux_server::register_listener(details::http_listener_imp return pplx::task_from_result(); } -pplx::task http_linux_server::unregister_listener(details::http_listener_impl* listener) +pplx::task http_linux_server::unregister_listener(http_listener_impl* listener) { auto parts = canonical_parts(listener->uri()); auto hostport = parts.first; @@ -1153,10 +1287,26 @@ pplx::task http_linux_server::unregister_listener(details::http_listener_i return pplx::task_from_result(); } -pplx::task http_linux_server::respond(http::http_response response) +pplx::task http_linux_server::respond(http_response response) { - details::linux_request_context * p_context = static_cast(response._get_server_context()); + linux_request_context * p_context = static_cast(response._get_server_context()); return pplx::create_task(p_context->m_response_completed); } -}}}} +} + +namespace web +{ +namespace http +{ +namespace experimental +{ +namespace details +{ + +std::unique_ptr make_http_asio_server() +{ + return make_unique(); +} + +}}}} \ No newline at end of file diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp index 98060d7b98..d00ac3fa1a 100644 --- a/Release/src/http/listener/http_server_httpsys.cpp +++ b/Release/src/http/listener/http_server_httpsys.cpp @@ -14,6 +14,8 @@ ****/ #include "stdafx.h" +#include "http_server_httpsys.h" +#include "http_server_impl.h" #if _WIN32_WINNT >= _WIN32_WINNT_VISTA @@ -1022,6 +1024,11 @@ void windows_request_context::cancel_request(std::exception_ptr except_ptr) } } +std::unique_ptr make_http_httpsys_server() +{ + return std::make_unique(); +} + }}}} #endif \ No newline at end of file diff --git a/Release/include/cpprest/details/http_server_httpsys.h b/Release/src/http/listener/http_server_httpsys.h similarity index 100% rename from Release/include/cpprest/details/http_server_httpsys.h rename to Release/src/http/listener/http_server_httpsys.h diff --git a/Release/src/http/listener/http_server_impl.h b/Release/src/http/listener/http_server_impl.h new file mode 100644 index 0000000000..478b557c89 --- /dev/null +++ b/Release/src/http/listener/http_server_impl.h @@ -0,0 +1,15 @@ +#pragma once + +namespace web +{ +namespace http +{ +namespace experimental +{ +namespace details +{ + +std::unique_ptr make_http_httpsys_server(); +std::unique_ptr make_http_asio_server(); + +}}}} diff --git a/Release/src/pch/stdafx.h b/Release/src/pch/stdafx.h index ee7ba0e70f..155b50b096 100644 --- a/Release/src/pch/stdafx.h +++ b/Release/src/pch/stdafx.h @@ -93,6 +93,7 @@ #include #include #include +#include #include "pplx/pplxtasks.h" #include "cpprest/version.h" @@ -137,15 +138,6 @@ #include "cpprest/http_listener.h" #include "cpprest/details/http_server_api.h" #endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA - -#if defined(_WIN32) && !defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) -#if _WIN32_WINNT >= _WIN32_WINNT_VISTA -#include "cpprest/details/http_server_httpsys.h" -#endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA -#else -#include "cpprest/details/http_server_asio.h" -#endif - #endif #if defined(max) From 13049fc080e75d9ea46995e27ec7d008c9747d81 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 19 Apr 2017 16:31:05 -0700 Subject: [PATCH 054/438] Fix vcxitems --- Release/src/build/android.vcxitems | 1 - Release/src/build/android.vcxitems.filters | 3 --- Release/src/build/common.vcxitems | 1 + Release/src/build/common.vcxitems.filters | 3 +++ 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Release/src/build/android.vcxitems b/Release/src/build/android.vcxitems index b838706244..eaf19e2057 100644 --- a/Release/src/build/android.vcxitems +++ b/Release/src/build/android.vcxitems @@ -25,7 +25,6 @@ - diff --git a/Release/src/build/android.vcxitems.filters b/Release/src/build/android.vcxitems.filters index a79b9de949..819746782d 100644 --- a/Release/src/build/android.vcxitems.filters +++ b/Release/src/build/android.vcxitems.filters @@ -29,9 +29,6 @@ - - Header Files - Header Files diff --git a/Release/src/build/common.vcxitems b/Release/src/build/common.vcxitems index c0a0ffef1d..8ced414213 100644 --- a/Release/src/build/common.vcxitems +++ b/Release/src/build/common.vcxitems @@ -84,6 +84,7 @@ + diff --git a/Release/src/build/common.vcxitems.filters b/Release/src/build/common.vcxitems.filters index eeba2e67ba..56f99807f9 100644 --- a/Release/src/build/common.vcxitems.filters +++ b/Release/src/build/common.vcxitems.filters @@ -215,6 +215,9 @@ Header Files\private + + Header Files\private + From e3ea6b8b0b763b3da0ce95462c3aa10e31d53552 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 20 Apr 2017 16:21:28 -0700 Subject: [PATCH 055/438] Add missing includes to http_server_impl.h --- Release/src/http/listener/http_server_impl.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Release/src/http/listener/http_server_impl.h b/Release/src/http/listener/http_server_impl.h index 478b557c89..6a4380b708 100644 --- a/Release/src/http/listener/http_server_impl.h +++ b/Release/src/http/listener/http_server_impl.h @@ -1,5 +1,8 @@ #pragma once +#include +#include "cpprest/details/http_server.h" + namespace web { namespace http From 15ce76dd7677dfd5c086bd4dba2e20f9a5ee3dfa Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 20 Apr 2017 16:23:03 -0700 Subject: [PATCH 056/438] Remove old include -- file was renamed. --- Release/src/http/listener/http_server_asio.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 30d8654f6d..cc28071fc0 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -28,7 +28,6 @@ #pragma clang diagnostic pop #endif -#include "cpprest/details/http_server_asio.h" #include "cpprest/asyncrt_utils.h" #include "pplx/threadpool.h" #include "../common/internal_http_helpers.h" From a93696897821392b30b16680df4cd9fc600225d1 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 20 Apr 2017 17:55:49 -0700 Subject: [PATCH 057/438] Hide server includes behind #ifdef to avoid inclusion on XP/UWP. --- Release/src/http/client/x509_cert_utilities.cpp | 1 + Release/src/http/listener/http_server_api.cpp | 2 +- Release/src/http/listener/http_server_httpsys.cpp | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Release/src/http/client/x509_cert_utilities.cpp b/Release/src/http/client/x509_cert_utilities.cpp index e4a322422e..48c50e07df 100644 --- a/Release/src/http/client/x509_cert_utilities.cpp +++ b/Release/src/http/client/x509_cert_utilities.cpp @@ -20,6 +20,7 @@ #if defined(ANDROID) || defined(__ANDROID__) #include +#include "pplx/threadpool.h" #endif #if defined(__APPLE__) diff --git a/Release/src/http/listener/http_server_api.cpp b/Release/src/http/listener/http_server_api.cpp index 05a4cdc1f2..b72d6cf8ef 100644 --- a/Release/src/http/listener/http_server_api.cpp +++ b/Release/src/http/listener/http_server_api.cpp @@ -10,9 +10,9 @@ ****/ #include "stdafx.h" -#include "http_server_impl.h" #if !defined(_WIN32) || (_WIN32_WINNT >= _WIN32_WINNT_VISTA && !defined(__cplusplus_winrt)) +#include "http_server_impl.h" using namespace web; using namespace utility; diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp index d00ac3fa1a..ce1717ea3d 100644 --- a/Release/src/http/listener/http_server_httpsys.cpp +++ b/Release/src/http/listener/http_server_httpsys.cpp @@ -14,11 +14,12 @@ ****/ #include "stdafx.h" -#include "http_server_httpsys.h" -#include "http_server_impl.h" #if _WIN32_WINNT >= _WIN32_WINNT_VISTA +#include "http_server_httpsys.h" +#include "http_server_impl.h" + using namespace web; using namespace utility; using namespace concurrency; From c0d375eb56052e76800b5b0aff2e36630e5923eb Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Fri, 21 Apr 2017 13:43:09 -0700 Subject: [PATCH 058/438] Re-add diagnostic suppressions around boost. --- .../src/websockets/client/ws_client_wspp.cpp | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index ba41dd3134..46a13422fd 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -16,21 +16,11 @@ #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) #include "cpprest/details/x509_cert_utilities.h" +#include "pplx/threadpool.h" // Force websocketpp to use C++ std::error_code instead of Boost. #define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_ -#if defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#pragma GCC diagnostic ignored "-Wignored-qualifiers" -#pragma GCC diagnostic ignored "-Wcast-qual" -#include -#include -#include -#pragma GCC diagnostic pop -#else /* __GNUC__ */ -#if defined(_WIN32) +#if defined(_MSC_VER) #pragma warning( push ) #pragma warning( disable : 4100 4127 4512 4996 4701 4267 ) #define _WEBSOCKETPP_CPP11_STL_ @@ -38,6 +28,16 @@ #if _MSC_VER < 1900 #define _WEBSOCKETPP_NOEXCEPT_TOKEN_ #endif +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#pragma GCC diagnostic ignored "-Wcast-qual" +#elif defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Winfinite-recursion" #endif #include @@ -46,9 +46,12 @@ #if defined(_WIN32) #pragma warning( pop ) +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#elif defined(__clang__) +#pragma clang diagnostic pop #endif -#endif /* __GNUC__ */ #if defined(_MSC_VER) #pragma warning( disable : 4503 ) From a6bdbca915c8898474418597ac090190eb0d44eb Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Fri, 21 Apr 2017 18:08:21 -0700 Subject: [PATCH 059/438] Tweaks for PR #376 Rename invoke_nativesessionhandle -> _invoke_nativesessionhandle to indicate that it is internal. Do not try/catch around _invoke_nativesessionhandle. The caller will handle it and the request error appropriately. Indicate in the comments that session callback only works on WinHTTP. --- Release/include/cpprest/http_client.h | 14 ++++---------- Release/src/http/client/http_client_winhttp.cpp | 8 ++------ 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/Release/include/cpprest/http_client.h b/Release/include/cpprest/http_client.h index 76fcc22ab1..4a72aab2b6 100644 --- a/Release/include/cpprest/http_client.h +++ b/Release/include/cpprest/http_client.h @@ -317,11 +317,7 @@ class http_client_config /// /// /// The native_handle is the following type depending on the underlying platform: - /// Windows Desktop, WinHTTP - HINTERNET - /// Windows Runtime, WinRT - IXMLHTTPRequest2 * - /// All other platforms, Boost.Asio: - /// https - boost::asio::ssl::stream * - /// http - boost::asio::ip::tcp::socket * + /// Windows Desktop, WinHTTP - HINTERNET (session) /// /// A user callback allowing for customization of the session void set_nativesessionhandle_options(const std::function &callback) @@ -332,15 +328,13 @@ class http_client_config /// /// Invokes a user's callback to allow for customization of the session. /// + /// Internal Use Only /// A internal implementation handle. - void invoke_nativesessionhandle_options(native_handle handle) const + void _invoke_nativesessionhandle_options(native_handle handle) const { - if (m_set_user_nativesessionhandle_options != nullptr) { - m_set_user_nativesessionhandle_options(handle); - } + m_set_user_nativesessionhandle_options(handle); } - /// /// Sets a callback to enable custom setting of platform specific options. /// diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index aebd03bfa7..ab214e2dcb 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -456,15 +456,11 @@ class winhttp_client : public _http_client_communicator win32_result = ::WinHttpSetOption(m_hSession, WINHTTP_OPTION_SECURE_PROTOCOLS, &secure_protocols, sizeof(secure_protocols)); if(FALSE == win32_result){ result = HRESULT_FROM_WIN32(::GetLastError()); } - try { - client_config().invoke_nativesessionhandle_options(m_hSession); - } - catch (...) - { - return report_failure(_XPLATSTR("Error in session handle callback")); } + config._invoke_nativesessionhandle_options(m_hSession); + // Register asynchronous callback. if(WINHTTP_INVALID_STATUS_CALLBACK == WinHttpSetStatusCallback( m_hSession, From 305e1163858cdf8b625501e597b129a3ef62a056 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Fri, 21 Apr 2017 18:08:51 -0700 Subject: [PATCH 060/438] Inline open_if_required() into the single point of use. --- Release/src/http/client/http_client.cpp | 31 +++++++++------------- Release/src/http/client/http_client_impl.h | 4 +-- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/Release/src/http/client/http_client.cpp b/Release/src/http/client/http_client.cpp index 25ded78023..164bec3f48 100644 --- a/Release/src/http/client/http_client.cpp +++ b/Release/src/http/client/http_client.cpp @@ -205,24 +205,6 @@ _http_client_communicator::_http_client_communicator(http::uri&& address, http_c void _http_client_communicator::open_and_send_request(const std::shared_ptr &request) { // First see if client needs to be opened. - auto error = open_if_required(); - - if (error != 0) - { - // Failed to open - request->report_error(error, _XPLATSTR("Open failed")); - - // DO NOT TOUCH the this pointer after completing the request - // This object could be freed along with the request as it could - // be the last reference to this object - return; - } - - send_request(request); -} - -unsigned long _http_client_communicator::open_if_required() -{ unsigned long error = 0; if (!m_opened) @@ -241,7 +223,18 @@ unsigned long _http_client_communicator::open_if_required() } } - return error; + if (error != 0) + { + // Failed to open + request->report_error(error, _XPLATSTR("Open failed")); + + // DO NOT TOUCH the this pointer after completing the request + // This object could be freed along with the request as it could + // be the last reference to this object + return; + } + + send_request(request); } inline void request_context::finish() diff --git a/Release/src/http/client/http_client_impl.h b/Release/src/http/client/http_client_impl.h index d14522a35b..b292323ee0 100644 --- a/Release/src/http/client/http_client_impl.h +++ b/Release/src/http/client/http_client_impl.h @@ -130,7 +130,7 @@ class _http_client_communicator : public http_pipeline_stage http_client_config m_client_config; - bool m_opened; + std::atomic m_opened; pplx::extensibility::critical_section_t m_open_lock; @@ -138,8 +138,6 @@ class _http_client_communicator : public http_pipeline_stage void open_and_send_request_async(const std::shared_ptr &request); void open_and_send_request(const std::shared_ptr &request); - unsigned long open_if_required(); - // Queue used to guarantee ordering of requests, when applicable. std::queue> m_requests_queue; int m_scheduled; From d72c5f903f6d65983a200f3ce7b7302fc1e5d3d5 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Fri, 21 Apr 2017 18:09:22 -0700 Subject: [PATCH 061/438] Minor cleanup. --- Release/src/http/client/http_client_winhttp.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index ab214e2dcb..3eee959aff 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -356,7 +356,7 @@ class winhttp_client : public _http_client_communicator } // Open session and connection with the server. - unsigned long open() + virtual unsigned long open() override { DWORD access_type; LPCWSTR proxy_name; @@ -449,14 +449,13 @@ class winhttp_client : public _http_client_communicator } #endif //Enable TLS 1.1 and 1.2 - HRESULT result(S_OK); BOOL win32_result(FALSE); - + DWORD secure_protocols(WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2); win32_result = ::WinHttpSetOption(m_hSession, WINHTTP_OPTION_SECURE_PROTOCOLS, &secure_protocols, sizeof(secure_protocols)); - if(FALSE == win32_result){ result = HRESULT_FROM_WIN32(::GetLastError()); } - + if(FALSE == win32_result) { + return report_failure(_XPLATSTR("Error setting session options")); } config._invoke_nativesessionhandle_options(m_hSession); From ad8a3b4114d3346b82f2ad98815dbeaf4ac76390 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sun, 23 Apr 2017 06:34:23 -0700 Subject: [PATCH 062/438] Rework CMake build to use INTERFACE targets to handle dependencies. This centralizes the workaround for older cmake versions which don't export new-style IMPORTED targets. --- Release/CMakeLists.txt | 28 ++-- Release/cmake/cpprest_find_boost.cmake | 58 ++++--- Release/cmake/cpprest_find_openssl.cmake | 68 ++++---- Release/cmake/cpprest_find_websocketpp.cmake | 14 +- Release/cmake/cpprest_find_zlib.cmake | 16 +- Release/cmake/cpprestsdk-config.in.cmake | 17 ++ Release/src/CMakeLists.txt | 64 +++++--- .../tests/common/TestRunner/CMakeLists.txt | 150 ++++++------------ .../tests/common/UnitTestpp/CMakeLists.txt | 5 +- Release/tests/common/utilities/CMakeLists.txt | 10 +- .../functional/http/client/CMakeLists.txt | 8 +- .../http/client/authentication_tests.cpp | 1 + .../functional/http/client/outside_tests.cpp | 1 + .../functional/http/utilities/CMakeLists.txt | 1 - Release/tests/functional/json/CMakeLists.txt | 4 + .../tests/functional/streams/CMakeLists.txt | 8 +- Release/tests/functional/uri/stdafx.cpp | 2 +- Release/tests/functional/utils/stdafx.cpp | 2 +- .../functional/websockets/CMakeLists.txt | 29 ++-- .../websockets/client/CMakeLists.txt | 7 +- 20 files changed, 262 insertions(+), 231 deletions(-) create mode 100644 Release/cmake/cpprestsdk-config.in.cmake diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 5d1e036c2c..33f0c37fde 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -1,18 +1,22 @@ set(CMAKE_LEGACY_CYGWIN_WIN32 0) -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.0) if(POLICY CMP0042) cmake_policy(SET CMP0042 NEW) # use MACOSX_RPATH endif() -project(cpprest) +if(UNIX) + project(cpprest C CXX) +else() + project(cpprest CXX) +endif() enable_testing() set(WERROR ON CACHE BOOL "Treat Warnings as Errors.") set(CPPREST_EXCLUDE_WEBSOCKETS OFF CACHE BOOL "Exclude websockets functionality.") set(CPPREST_EXCLUDE_COMPRESSION OFF CACHE BOOL "Exclude compression functionality.") -set(CPPREST_EXPORT_DIR lib/cpprest CACHE STRING "Directory to install CMake config files.") -set(CPPREST_EXPORT_NAME cpprest-config CACHE STRING "Name for CMake config file.") +set(CPPREST_EXPORT_DIR lib/cpprestsdk CACHE STRING "Directory to install CMake config files.") set(CPPREST_INSTALL_HEADERS ON CACHE BOOL "Install header files.") +set(CPPREST_INSTALL ON CACHE BOOL "Add install commands.") if(IOS OR ANDROID) set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries") @@ -172,7 +176,6 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Binaries) # These settings can be used by the test targets set(Casablanca_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include) -set(Casablanca_SYSTEM_INCLUDE_DIRS) set(Casablanca_LIBRARY cpprest) set(Casablanca_LIBRARIES cpprest) get_directory_property(PARENT_DIR PARENT_DIRECTORY) @@ -180,27 +183,28 @@ if(NOT PARENT_DIR STREQUAL "") set(Casablanca_LIBRARIES ${Casablanca_LIBRARIES} PARENT_SCOPE) endif() -# Everything in the project needs access to the casablanca include directories -include_directories( ${Casablanca_INCLUDE_DIRS}) -include_directories(SYSTEM ${Casablanca_SYSTEM_INCLUDE_DIRS}) - # Finally, the tests all use the same style declaration to build themselves, so we use a function function(add_casablanca_test NAME SOURCES_VAR) add_library(${NAME} ${TEST_LIBRARY_TARGET_TYPE} ${${SOURCES_VAR}}) message("-- Added test library ${NAME}") - if (NOT TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT") + if(TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT") + foreach(_dep httptest_utilities common_utilities unittestpp cpprest) + target_include_directories(${NAME} PRIVATE $) + target_compile_definitions(${NAME} PRIVATE $) + endforeach() + else() target_link_libraries(${NAME} httptest_utilities common_utilities unittestpp cpprest ${ANDROID_STL_FLAGS} - ) + ) if (BUILD_SHARED_LIBS) add_test(NAME ${NAME} WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} COMMAND test_runner $ - ) + ) endif() endif() endfunction() diff --git a/Release/cmake/cpprest_find_boost.cmake b/Release/cmake/cpprest_find_boost.cmake index e1c8289c6c..1ff79121e3 100644 --- a/Release/cmake/cpprest_find_boost.cmake +++ b/Release/cmake/cpprest_find_boost.cmake @@ -1,13 +1,12 @@ function(cpprest_find_boost) - if(Boost_FOUND) + if(TARGET cpprestsdk_boost_internal) return() endif() if(IOS) set(IOS_SOURCE_DIR "${PROJECT_SOURCE_DIR}/../Build_iOS") - set(Boost_FOUND 1 CACHE INTERNAL "") - set(Boost_FRAMEWORK "-F ${IOS_SOURCE_DIR} -framework boost" CACHE INTERNAL "") - set(Boost_INCLUDE_DIR "$" CACHE INTERNAL "") + set(Boost_LIBRARIES "${IOS_SOURCE_DIR}/boost.framework/boost" CACHE INTERNAL "") + set(Boost_INCLUDE_DIR "${IOS_SOURCE_DIR}/boost.framework/Headers" CACHE INTERNAL "") elseif(ANDROID) set(Boost_COMPILER "-clang") if(ARM) @@ -24,17 +23,40 @@ function(cpprest_find_boost) find_package(Boost REQUIRED COMPONENTS system date_time regex) endif() - set(Boost_FOUND 1 CACHE INTERNAL "") - set(Boost_INCLUDE_DIR ${Boost_INCLUDE_DIR} CACHE INTERNAL "") - set(Boost_LIBRARIES - ${Boost_SYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${Boost_ATOMIC_LIBRARY} - ${Boost_CHRONO_LIBRARY} - ${Boost_RANDOM_LIBRARY} - ${Boost_REGEX_LIBRARY} - ${Boost_DATE_TIME_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${BOOST_FRAMEWORK} - CACHE INTERNAL "") - endfunction() \ No newline at end of file + add_library(cpprestsdk_boost_internal INTERFACE) + if(NOT TARGET Boost::boost) + target_include_directories(cpprestsdk_boost_internal INTERFACE "$") + target_link_libraries(cpprestsdk_boost_internal INTERFACE "$") + else() + if(ANDROID) + target_link_libraries(cpprestsdk_boost_internal INTERFACE + Boost::boost + Boost::random + Boost::system + Boost::thread + Boost::filesystem + Boost::chrono + Boost::atomic + ) + elseif(UNIX) + target_link_libraries(cpprestsdk_boost_internal INTERFACE + Boost::boost + Boost::random + Boost::system + Boost::thread + Boost::filesystem + Boost::chrono + Boost::atomic + Boost::date_time + Boost::regex + ) + else() + target_link_libraries(cpprestsdk_boost_internal INTERFACE + Boost::boost + Boost::system + Boost::date_time + Boost::regex + ) + endif() + endif() +endfunction() diff --git a/Release/cmake/cpprest_find_openssl.cmake b/Release/cmake/cpprest_find_openssl.cmake index 8ae2db6640..0b49a7e55c 100644 --- a/Release/cmake/cpprest_find_openssl.cmake +++ b/Release/cmake/cpprest_find_openssl.cmake @@ -1,62 +1,70 @@ function(cpprest_find_openssl) - if(OPENSSL_FOUND) + if(TARGET cpprestsdk_openssl_internal) return() endif() if(IOS) set(IOS_SOURCE_DIR "${PROJECT_SOURCE_DIR}/../Build_iOS") - set(OPENSSL_FOUND 1 CACHE INTERNAL "") - set(OPENSSL_INCLUDE_DIR "$" CACHE INTERNAL "") + + set(OPENSSL_INCLUDE_DIR "${IOS_SOURCE_DIR}/openssl/include" CACHE INTERNAL "") set(OPENSSL_LIBRARIES "${IOS_SOURCE_DIR}/openssl/lib/libcrypto.a" "${IOS_SOURCE_DIR}/openssl/lib/libssl.a" CACHE INTERNAL "" ) set(_SSL_LEAK_SUPPRESS_AVAILABLE ON CACHE INTERNAL "") - return() elseif(ANDROID) - set(OPENSSL_FOUND 1 CACHE INTERNAL "") if(ARM) - set(OPENSSL_INCLUDE_DIR "$" CACHE INTERNAL "") + set(OPENSSL_INCLUDE_DIR "${CMAKE_BINARY_DIR}/../openssl/armeabi-v7a/include" CACHE INTERNAL "") set(OPENSSL_LIBRARIES "${CMAKE_BINARY_DIR}/../openssl/armeabi-v7a/lib/libssl.a" "${CMAKE_BINARY_DIR}/../openssl/armeabi-v7a/lib/libcrypto.a" CACHE INTERNAL "" ) else() - set(OPENSSL_INCLUDE_DIR "$" CACHE INTERNAL "") + set(OPENSSL_INCLUDE_DIR "${CMAKE_BINARY_DIR}/../openssl/x86/include" CACHE INTERNAL "") set(OPENSSL_LIBRARIES "${CMAKE_BINARY_DIR}/../openssl/x86/lib/libssl.a" "${CMAKE_BINARY_DIR}/../openssl/x86/lib/libcrypto.a" CACHE INTERNAL "" ) endif() - elseif(APPLE) - if(NOT DEFINED OPENSSL_ROOT_DIR) - # Prefer a homebrew version of OpenSSL over the one in /usr/lib - file(GLOB OPENSSL_ROOT_DIR /usr/local/Cellar/openssl/*) - # Prefer the latest (make the latest one first) - list(REVERSE OPENSSL_ROOT_DIR) - endif() - # This should prevent linking against the system provided 0.9.8y - set(_OPENSSL_VERSION "") - find_package(OpenSSL 1.0.0 REQUIRED) + set(_SSL_LEAK_SUPPRESS_AVAILABLE ON CACHE INTERNAL "") else() + if(APPLE) + if(NOT DEFINED OPENSSL_ROOT_DIR) + # Prefer a homebrew version of OpenSSL over the one in /usr/lib + file(GLOB OPENSSL_ROOT_DIR /usr/local/Cellar/openssl/*) + # Prefer the latest (make the latest one first) + list(REVERSE OPENSSL_ROOT_DIR) + endif() + # This should prevent linking against the system provided 0.9.8y + set(_OPENSSL_VERSION "") + endif() find_package(OpenSSL 1.0.0 REQUIRED) + + INCLUDE(CheckCXXSourceCompiles) + set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}") + set(CMAKE_REQUIRED_LIBRARIES "${OPENSSL_LIBRARIES}") + CHECK_CXX_SOURCE_COMPILES(" + #include + int main() + { + ::SSL_COMP_free_compression_methods(); + } + " _SSL_LEAK_SUPPRESS_AVAILABLE) endif() - set(OPENSSL_FOUND 1 CACHE INTERNAL "") - set(OPENSSL_INCLUDE_DIR ${OPENSSL_INCLUDE_DIR} CACHE INTERNAL "") - set(OPENSSL_LIBRARIES ${OPENSSL_LIBRARIES} CACHE INTERNAL "") + add_library(cpprestsdk_openssl_internal INTERFACE) + if(TARGET OpenSSL::SSL) + target_link_libraries(cpprestsdk_openssl_internal INTERFACE OpenSSL::SSL) + else() + target_link_libraries(cpprestsdk_openssl_internal INTERFACE "$") + target_include_directories(cpprestsdk_openssl_internal INTERFACE "$") + endif() - INCLUDE(CheckCXXSourceCompiles) - set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}") - set(CMAKE_REQUIRED_LIBRARIES "${OPENSSL_LIBRARIES}") - CHECK_CXX_SOURCE_COMPILES(" - #include - int main() - { - ::SSL_COMP_free_compression_methods(); - } - " _SSL_LEAK_SUPPRESS_AVAILABLE) + if (NOT _SSL_LEAK_SUPPRESS_AVAILABLE) + # libressl doesn't ship with the cleanup method being used in ws_client_wspp + target_compile_definitions(cpprestsdk_openssl_internal INTERFACE -DCPPREST_NO_SSL_LEAK_SUPPRESS) + endif() endfunction() \ No newline at end of file diff --git a/Release/cmake/cpprest_find_websocketpp.cmake b/Release/cmake/cpprest_find_websocketpp.cmake index 165aed2aba..260311f0a3 100644 --- a/Release/cmake/cpprest_find_websocketpp.cmake +++ b/Release/cmake/cpprest_find_websocketpp.cmake @@ -1,5 +1,5 @@ function(cpprest_find_websocketpp) - if(WEBSOCKETPP_FOUND) + if(TARGET cpprestsdk_websocketpp_internal) return() endif() @@ -9,7 +9,17 @@ function(cpprest_find_websocketpp) set(WEBSOCKETPP_INCLUDE_DIR ${WEBSOCKETPP_INCLUDE_DIR} CACHE INTERNAL "") else() message("-- websocketpp not found, using the embedded version") - set(WEBSOCKETPP_FOUND 1 CACHE INTERNAL "" FORCE) set(WEBSOCKETPP_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/libs/websocketpp CACHE INTERNAL "") endif() + + cpprest_find_boost() + cpprest_find_openssl() + + add_library(cpprestsdk_websocketpp_internal INTERFACE) + target_include_directories(cpprestsdk_websocketpp_internal INTERFACE "$") + target_link_libraries(cpprestsdk_websocketpp_internal + INTERFACE + cpprestsdk_boost_internal + cpprestsdk_openssl_internal + ) endfunction() \ No newline at end of file diff --git a/Release/cmake/cpprest_find_zlib.cmake b/Release/cmake/cpprest_find_zlib.cmake index 1b5302566c..bb5e29f013 100644 --- a/Release/cmake/cpprest_find_zlib.cmake +++ b/Release/cmake/cpprest_find_zlib.cmake @@ -1,21 +1,25 @@ function(cpprest_find_zlib) - if(ZLIB_FOUND) + if(TARGET cpprestsdk_zlib_internal) return() endif() if(APPLE AND NOT IOS) # Prefer the homebrew version of zlib - find_library(ZLIB_LIBRARIES NAMES libz.a PATHS /usr/local/Cellar/zlib/1.2.8/lib NO_DEFAULT_PATH) + find_library(ZLIB_LIBRARY NAMES libz.a PATHS /usr/local/Cellar/zlib/1.2.8/lib NO_DEFAULT_PATH) find_path(ZLIB_INCLUDE_DIRS NAMES zlib.h PATHS /usr/local/Cellar/zlib/1.2.8/include NO_DEFAULT_PATH) - if(NOT ZLIB_LIBRARIES OR NOT ZLIB_INCLUDE_DIRS) + if(NOT ZLIB_LIBRARY OR NOT ZLIB_INCLUDE_DIRS) find_package(ZLIB REQUIRED) endif() else() find_package(ZLIB REQUIRED) endif() - set(ZLIB_FOUND 1 CACHE INTERNAL "") - set(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIRS} CACHE INTERNAL "") - set(ZLIB_LIBRARIES ${ZLIB_LIBRARIES} CACHE INTERNAL "") + add_library(cpprestsdk_zlib_internal INTERFACE) + if(TARGET ZLIB::ZLIB) + target_link_libraries(cpprestsdk_zlib_internal INTERFACE ZLIB::ZLIB) + else() + target_link_libraries(cpprestsdk_zlib_internal INTERFACE "$ - $ - $ - $ - $ - $ - ) - if (NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) - list(APPEND SOURCES - test_module_loader.cpp - $ - ) - endif() - add_executable(test_runner ${SOURCES}) - target_link_libraries(test_runner - unittestpp - common_utilities - httptest_utilities - cpprest - ${CMAKE_DL_LIBS} - ) - if (WINDOWS_STORE) - target_link_libraries(test_runner ucrtd.lib vcruntimed.lib vccorlibd.lib msvcrtd.lib msvcprtd.lib concrtd.lib RuntimeObject.lib) - endif() - endif() +add_executable(test_runner test_runner.cpp test_module_loader.cpp) +target_link_libraries(test_runner unittestpp) + +if(BUILD_SHARED_LIBS) + target_link_libraries(test_runner ${CMAKE_DL_LIBS}) +elseif(APPLE) + target_link_libraries(test_runner + -Wl,-force_load httpclient_test + -Wl,-force_load json_test + -Wl,-force_load uri_test + -Wl,-force_load pplx_test + -Wl,-force_load httplistener_test + -Wl,-force_load streams_test + -Wl,-force_load utils_test + ) +elseif(UNIX) + target_link_libraries(test_runner + -Wl,--whole-archive + httpclient_test + json_test + uri_test + pplx_test + httplistener_test + streams_test + utils_test + -Wl,--no-whole-archive + ) +else() + # In order to achieve --whole-archive on windows, we link all the test files into the test_runner directly + # This means that the tests themselves must be created as "OBJECT" libraries + target_sources(test_runner PRIVATE + $ + $ + $ + $ + $ + $ + ) + if(NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) + target_sources(test_runner PRIVATE $) + endif() + target_link_libraries(test_runner + common_utilities + httptest_utilities + cpprest + ) + if(CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") + cpprest_find_websocketpp() + target_link_libraries(test_runner cpprestsdk_websocketpp_internal) + endif() + if (WINDOWS_STORE) + target_link_libraries(test_runner ucrtd.lib vcruntimed.lib vccorlibd.lib msvcrtd.lib msvcprtd.lib concrtd.lib RuntimeObject.lib) endif() endif() diff --git a/Release/tests/common/UnitTestpp/CMakeLists.txt b/Release/tests/common/UnitTestpp/CMakeLists.txt index 43a2d4de43..309c5f28fa 100644 --- a/Release/tests/common/UnitTestpp/CMakeLists.txt +++ b/Release/tests/common/UnitTestpp/CMakeLists.txt @@ -47,10 +47,11 @@ elseif(WIN32) endif() add_library(unittestpp ${UT_SOURCES}) +target_link_libraries(unittestpp PUBLIC cpprest) + if(UNIX) cpprest_find_boost() - target_include_directories(unittestpp PUBLIC ${Boost_INCLUDE_DIR}) - target_link_libraries(unittestpp PUBLIC ${Boost_LIBRARIES}) + target_link_libraries(unittestpp PUBLIC cpprestsdk_boost_internal) endif() target_link_libraries(unittestpp ${ANDROID_STL_FLAGS}) diff --git a/Release/tests/common/utilities/CMakeLists.txt b/Release/tests/common/utilities/CMakeLists.txt index 6ff564f84e..dfe4852da6 100644 --- a/Release/tests/common/utilities/CMakeLists.txt +++ b/Release/tests/common/utilities/CMakeLists.txt @@ -9,9 +9,11 @@ add_library(common_utilities stdafx.cpp ) +if(NOT BUILD_SHARED_LIBS) + target_compile_definitions(common_utilities INTERFACE -DTEST_UTILITY_API=) +endif() + target_link_libraries(common_utilities - ${Casablanca_LIBRARY} + cpprest unittestpp - ${Boost_SYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ) +) diff --git a/Release/tests/functional/http/client/CMakeLists.txt b/Release/tests/functional/http/client/CMakeLists.txt index ba86825db9..93bc5475bb 100644 --- a/Release/tests/functional/http/client/CMakeLists.txt +++ b/Release/tests/functional/http/client/CMakeLists.txt @@ -30,8 +30,8 @@ set(SOURCES stdafx.cpp ) -add_casablanca_test(httpclient_test SOURCES) - -if(WIN32) - target_link_libraries(httpclient_test winhttp) +if(NOT WIN32) + cpprest_find_boost() + link_libraries(cpprestsdk_boost_internal) endif() +add_casablanca_test(httpclient_test SOURCES) diff --git a/Release/tests/functional/http/client/authentication_tests.cpp b/Release/tests/functional/http/client/authentication_tests.cpp index 9caa86b0b6..48190bdc55 100644 --- a/Release/tests/functional/http/client/authentication_tests.cpp +++ b/Release/tests/functional/http/client/authentication_tests.cpp @@ -22,6 +22,7 @@ #else #include #include +#pragma comment(lib, "winhttp") #endif #endif diff --git a/Release/tests/functional/http/client/outside_tests.cpp b/Release/tests/functional/http/client/outside_tests.cpp index 35d0f6e867..b1da9c23e7 100644 --- a/Release/tests/functional/http/client/outside_tests.cpp +++ b/Release/tests/functional/http/client/outside_tests.cpp @@ -14,6 +14,7 @@ #define WIN32_LEAN_AND_MEAN #include #include +#pragma comment(lib, "winhttp") #endif #include "cpprest/rawptrstream.h" #include "cpprest/details/http_helpers.h" diff --git a/Release/tests/functional/http/utilities/CMakeLists.txt b/Release/tests/functional/http/utilities/CMakeLists.txt index 279df76749..e93e2c4e91 100644 --- a/Release/tests/functional/http/utilities/CMakeLists.txt +++ b/Release/tests/functional/http/utilities/CMakeLists.txt @@ -16,5 +16,4 @@ target_link_libraries(httptest_utilities unittestpp common_utilities cpprest - ${BOOST_LIBRARIES} ) diff --git a/Release/tests/functional/json/CMakeLists.txt b/Release/tests/functional/json/CMakeLists.txt index a1ece2f5d0..2972052f01 100644 --- a/Release/tests/functional/json/CMakeLists.txt +++ b/Release/tests/functional/json/CMakeLists.txt @@ -11,4 +11,8 @@ if (NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) list(APPEND SOURCES fuzz_tests.cpp) endif() +if(UNIX AND NOT APPLE) + cpprest_find_boost() + link_libraries(cpprestsdk_boost_internal) +endif() add_casablanca_test(json_test SOURCES) diff --git a/Release/tests/functional/streams/CMakeLists.txt b/Release/tests/functional/streams/CMakeLists.txt index bb532557c3..14cb97f2ce 100644 --- a/Release/tests/functional/streams/CMakeLists.txt +++ b/Release/tests/functional/streams/CMakeLists.txt @@ -14,9 +14,9 @@ if (NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) else () list(APPEND SOURCES winrt_interop_tests.cpp) endif () -add_casablanca_test(streams_test SOURCES) -if(NOT CPPREST_WEBSOCKETS_IMPL STREQUAL "none") +if(NOT WIN32 OR CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") cpprest_find_boost() - target_include_directories(streams_test PRIVATE ${Boost_INCLUDE_DIR}) -endif() \ No newline at end of file + link_libraries(cpprestsdk_boost_internal) +endif() +add_casablanca_test(streams_test SOURCES) diff --git a/Release/tests/functional/uri/stdafx.cpp b/Release/tests/functional/uri/stdafx.cpp index bd7d546624..84ac9e6db3 100644 --- a/Release/tests/functional/uri/stdafx.cpp +++ b/Release/tests/functional/uri/stdafx.cpp @@ -11,5 +11,5 @@ #include "stdafx.h" #if WIN32 -__declspec(dllexport) int pplx_test_generate_lib = 0; +__declspec(dllexport) int uri_test_generate_lib = 0; #endif \ No newline at end of file diff --git a/Release/tests/functional/utils/stdafx.cpp b/Release/tests/functional/utils/stdafx.cpp index 1037a64c5c..b27e91b093 100644 --- a/Release/tests/functional/utils/stdafx.cpp +++ b/Release/tests/functional/utils/stdafx.cpp @@ -11,5 +11,5 @@ #include "stdafx.h" #if WIN32 -__declspec(dllexport) int pplx_test_generate_lib = 0; +__declspec(dllexport) int utils_test_generate_lib = 0; #endif diff --git a/Release/tests/functional/websockets/CMakeLists.txt b/Release/tests/functional/websockets/CMakeLists.txt index eae5bfb377..b232922576 100644 --- a/Release/tests/functional/websockets/CMakeLists.txt +++ b/Release/tests/functional/websockets/CMakeLists.txt @@ -1,34 +1,25 @@ if (NOT CPPREST_EXCLUDE_WEBSOCKETS) - include_directories(utilities/include) - set(SOURCES utilities/test_websocket_server.cpp ) - - add_library(websockettest_utilities ${TEST_LIBRARY_TARGET_TYPE} ${SOURCES}) + + add_library(websockettest_utilities ${SOURCES}) + target_include_directories(websockettest_utilities PUBLIC utilities) target_compile_definitions(websockettest_utilities PRIVATE -DWEBSOCKETTESTUTILITY_EXPORTS) if(NOT WIN32) target_compile_definitions(websockettest_utilities PRIVATE "-DWEBSOCKET_UTILITY_API=__attribute__ ((visibility (\"default\")))") target_compile_definitions(websockettest_utilities INTERFACE "-DWEBSOCKET_UTILITY_API=") endif() - if (NOT TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT") - target_link_libraries(websockettest_utilities PRIVATE + + cpprest_find_websocketpp() + target_link_libraries(websockettest_utilities + PRIVATE unittestpp - common_utilities cpprest - ) - endif() - - if(CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") - cpprest_find_boost() - cpprest_find_zlib() - cpprest_find_openssl() - cpprest_find_websocketpp() - - target_include_directories(websockettest_utilities SYSTEM PRIVATE ${Boost_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ${WEBSOCKETPP_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}) - target_link_libraries(websockettest_utilities PRIVATE ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES}) - endif() + common_utilities + cpprestsdk_websocketpp_internal + ) add_subdirectory(client) endif() diff --git a/Release/tests/functional/websockets/client/CMakeLists.txt b/Release/tests/functional/websockets/client/CMakeLists.txt index a2597dac62..bda6b6e6a8 100644 --- a/Release/tests/functional/websockets/client/CMakeLists.txt +++ b/Release/tests/functional/websockets/client/CMakeLists.txt @@ -1,6 +1,4 @@ if (NOT CPPREST_EXCLUDE_WEBSOCKETS) - include_directories(../utilities) - set(SOURCES authentication_tests.cpp client_construction.cpp @@ -11,8 +9,7 @@ if (NOT CPPREST_EXCLUDE_WEBSOCKETS) stdafx.cpp ) + # This works around "OBJECT" tests + link_libraries(websockettest_utilities) add_casablanca_test(websocketclient_test SOURCES) - if (NOT TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT") - target_link_libraries(websocketclient_test websockettest_utilities) - endif() endif() \ No newline at end of file From ebf39000ee88779b960d42f3c298918a57d9a78e Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 24 Apr 2017 17:45:02 -0700 Subject: [PATCH 063/438] Export websocketpp interface forwarder when available. --- Release/src/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index c222892d34..7e10c52f2c 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -272,6 +272,9 @@ if(CPPREST_INSTALL) if(TARGET cpprestsdk_openssl_internal) list(APPEND CPPREST_TARGETS cpprestsdk_openssl_internal) endif() + if(TARGET cpprestsdk_websocketpp_internal) + list(APPEND CPPREST_TARGETS cpprestsdk_websocketpp_internal) + endif() install( TARGETS ${CPPREST_TARGETS} EXPORT cpprestsdk-targets From 7de91c0d23c34603df47dda13175444703bae330 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 24 Apr 2017 17:45:23 -0700 Subject: [PATCH 064/438] Always use PUBLIC/PRIVATE for target_link_libraries. --- Release/tests/common/TestRunner/CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Release/tests/common/TestRunner/CMakeLists.txt b/Release/tests/common/TestRunner/CMakeLists.txt index 4da288a539..9de56507bb 100644 --- a/Release/tests/common/TestRunner/CMakeLists.txt +++ b/Release/tests/common/TestRunner/CMakeLists.txt @@ -7,12 +7,12 @@ if (WIN32) endif() add_executable(test_runner test_runner.cpp test_module_loader.cpp) -target_link_libraries(test_runner unittestpp) +target_link_libraries(test_runner PRIVATE unittestpp) if(BUILD_SHARED_LIBS) - target_link_libraries(test_runner ${CMAKE_DL_LIBS}) + target_link_libraries(test_runner PRIVATE ${CMAKE_DL_LIBS}) elseif(APPLE) - target_link_libraries(test_runner + target_link_libraries(test_runner PRIVATE -Wl,-force_load httpclient_test -Wl,-force_load json_test -Wl,-force_load uri_test @@ -22,7 +22,7 @@ elseif(APPLE) -Wl,-force_load utils_test ) elseif(UNIX) - target_link_libraries(test_runner + target_link_libraries(test_runner PRIVATE -Wl,--whole-archive httpclient_test json_test @@ -47,16 +47,16 @@ else() if(NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) target_sources(test_runner PRIVATE $) endif() - target_link_libraries(test_runner + target_link_libraries(test_runner PRIVATE common_utilities httptest_utilities cpprest ) if(CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") cpprest_find_websocketpp() - target_link_libraries(test_runner cpprestsdk_websocketpp_internal) + target_link_libraries(test_runner PRIVATE cpprestsdk_websocketpp_internal) endif() if (WINDOWS_STORE) - target_link_libraries(test_runner ucrtd.lib vcruntimed.lib vccorlibd.lib msvcrtd.lib msvcprtd.lib concrtd.lib RuntimeObject.lib) + target_link_libraries(test_runner PRIVATE ucrtd.lib vcruntimed.lib vccorlibd.lib msvcrtd.lib msvcprtd.lib concrtd.lib RuntimeObject.lib) endif() endif() From 8b33dcc7773bcecada01d4261f88742f2b683718 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 24 Apr 2017 17:46:13 -0700 Subject: [PATCH 065/438] Fix invoking unset nativehandle callbacks --- Release/include/cpprest/http_client.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Release/include/cpprest/http_client.h b/Release/include/cpprest/http_client.h index 4a72aab2b6..80c48265a1 100644 --- a/Release/include/cpprest/http_client.h +++ b/Release/include/cpprest/http_client.h @@ -87,7 +87,6 @@ class http_client_config #if !defined(__cplusplus_winrt) , m_validate_certificates(true) #endif - , m_set_user_nativehandle_options([](native_handle)->void{}) #if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO) , m_tlsext_sni_enabled(true) #endif @@ -332,7 +331,8 @@ class http_client_config /// A internal implementation handle. void _invoke_nativesessionhandle_options(native_handle handle) const { - m_set_user_nativesessionhandle_options(handle); + if (m_set_user_nativesessionhandle_options) + m_set_user_nativesessionhandle_options(handle); } /// @@ -358,7 +358,8 @@ class http_client_config /// A internal implementation handle. void invoke_nativehandle_options(native_handle handle) const { - m_set_user_nativehandle_options(handle); + if (m_set_user_nativehandle_options) + m_set_user_nativehandle_options(handle); } #if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO) From 5f487ba4142572ac394ed3c9522c76bcfefc26e1 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 24 Apr 2017 17:52:01 -0700 Subject: [PATCH 066/438] Handle wchar_t-, fixes #179 --- Release/include/cpprest/streams.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Release/include/cpprest/streams.h b/Release/include/cpprest/streams.h index 7e4128984b..619c30d51c 100644 --- a/Release/include/cpprest/streams.h +++ b/Release/include/cpprest/streams.h @@ -447,7 +447,9 @@ namespace Concurrency { namespace streams _INT_TRAIT(char,INT8_MIN,INT8_MAX) _INT_TRAIT(signed char,INT8_MIN,INT8_MAX) _INT_TRAIT(short,INT16_MIN,INT16_MAX) - _INT_TRAIT(utf16char,INT16_MIN,INT16_MAX) +#if defined(_NATIVE_WCHAR_T_DEFINED) + _INT_TRAIT(wchar_t,WCHAR_MIN, WCHAR_MAX) +#endif _INT_TRAIT(int,INT32_MIN,INT32_MAX) _INT_TRAIT(long, LONG_MIN, LONG_MAX) _INT_TRAIT(long long, LLONG_MIN, LLONG_MAX) From ae700b3e26e63c1e9337129b58704399d502ff5d Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 25 Apr 2017 17:10:42 -0700 Subject: [PATCH 067/438] Improve proxy tests --- .../http/client/authentication_tests.cpp | 9 +- .../functional/http/client/proxy_tests.cpp | 108 ++++++++++++------ 2 files changed, 83 insertions(+), 34 deletions(-) diff --git a/Release/tests/functional/http/client/authentication_tests.cpp b/Release/tests/functional/http/client/authentication_tests.cpp index 48190bdc55..37b6177cc2 100644 --- a/Release/tests/functional/http/client/authentication_tests.cpp +++ b/Release/tests/functional/http/client/authentication_tests.cpp @@ -82,7 +82,14 @@ TEST_FIXTURE(uri_address, auth_no_data, "Ignore:Linux", "89", "Ignore:Apple", "8 p_request->reply(200); }); - http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + try + { + http_asserts::assert_response_equals(client.request(msg).get(), status_codes::OK); + } + catch (...) + { + VERIFY_ARE_EQUAL(0, 1); + } } try { t.get(); } catch (...) { VERIFY_ARE_EQUAL(0, 1); } diff --git a/Release/tests/functional/http/client/proxy_tests.cpp b/Release/tests/functional/http/client/proxy_tests.cpp index a48cff5abf..72fa201352 100644 --- a/Release/tests/functional/http/client/proxy_tests.cpp +++ b/Release/tests/functional/http/client/proxy_tests.cpp @@ -21,47 +21,106 @@ using namespace tests::functional::http::utilities; namespace tests { namespace functional { namespace http { namespace client { +// In order to run this test, replace this proxy uri with one that you have access to. +static const auto proxy_uri = U("http://netproxy.redmond.corp.microsoft.com/"); + SUITE(proxy_tests) { +TEST_FIXTURE(uri_address, web_proxy_uri) +{ + uri u(proxy_uri); + + web_proxy uri_proxy(u); + VERIFY_IS_TRUE(uri_proxy.is_specified()); + VERIFY_IS_FALSE(uri_proxy.is_disabled()); + VERIFY_IS_FALSE(uri_proxy.is_auto_discovery()); + VERIFY_IS_FALSE(uri_proxy.is_default()); + VERIFY_ARE_EQUAL(u, uri_proxy.address()); +} + +TEST_FIXTURE(uri_address, web_proxy_disabled) +{ + web_proxy disabled_proxy(web_proxy::disabled); + VERIFY_IS_FALSE(disabled_proxy.is_specified()); + VERIFY_IS_TRUE(disabled_proxy.is_disabled()); + VERIFY_IS_FALSE(disabled_proxy.is_auto_discovery()); + VERIFY_IS_FALSE(disabled_proxy.is_default()); +} + +TEST_FIXTURE(uri_address, web_proxy_discover) +{ + web_proxy discover_proxy(web_proxy::use_auto_discovery); + VERIFY_IS_FALSE(discover_proxy.is_specified()); + VERIFY_IS_FALSE(discover_proxy.is_disabled()); + VERIFY_IS_TRUE(discover_proxy.is_auto_discovery()); + VERIFY_IS_FALSE(discover_proxy.is_default()); +} + +TEST_FIXTURE(uri_address, web_proxy_default) +{ + web_proxy default_proxy(web_proxy::use_default); + VERIFY_IS_FALSE(default_proxy.is_specified()); + VERIFY_IS_FALSE(default_proxy.is_disabled()); + VERIFY_IS_FALSE(default_proxy.is_auto_discovery()); + VERIFY_IS_TRUE(default_proxy.is_default()); +} + +TEST_FIXTURE(uri_address, web_proxy_default_construct) +{ + web_proxy default_proxy_2; + VERIFY_IS_FALSE(default_proxy_2.is_specified()); + VERIFY_IS_FALSE(default_proxy_2.is_disabled()); + VERIFY_IS_FALSE(default_proxy_2.is_auto_discovery()); + VERIFY_IS_TRUE(default_proxy_2.is_default()); +} + +TEST_FIXTURE(uri_address, http_client_config_set_proxy) +{ + http_client_config hconfig; + VERIFY_IS_TRUE(hconfig.proxy().is_default()); + + uri u = U("http://x/"); + + hconfig.set_proxy(web_proxy(u)); + VERIFY_ARE_EQUAL(u, hconfig.proxy().address()); +} + #ifndef __cplusplus_winrt // IXHR2 does not allow the proxy settings to be changed TEST_FIXTURE(uri_address, auto_discovery_proxy) { test_http_server::scoped_server scoped(m_uri); - scoped.server()->next_request().then([&](test_request *p_request) + auto t = scoped.server()->next_request().then([&](test_request *p_request) { http_asserts::assert_test_request_equals(p_request, methods::PUT, U("/"), U("text/plain"), U("this is a test")); - p_request->reply(200); + p_request->reply(status_codes::OK); }); http_client_config config; - config.set_proxy(web_proxy::use_auto_discovery); - VERIFY_IS_FALSE(config.proxy().is_disabled()); - VERIFY_IS_FALSE(config.proxy().is_specified()); - http_client client(m_uri, config); + http_client client(m_uri, config); http_asserts::assert_response_equals(client.request(methods::PUT, U("/"), U("this is a test")).get(), status_codes::OK); + + t.get(); } TEST_FIXTURE(uri_address, disabled_proxy) { test_http_server::scoped_server scoped(m_uri); - scoped.server()->next_request().then([&](test_request *p_request) + auto t = scoped.server()->next_request().then([&](test_request *p_request) { http_asserts::assert_test_request_equals(p_request, methods::PUT, U("/"), U("text/plain"), U("sample data")); p_request->reply(status_codes::OK); }); http_client_config config; - config.set_proxy(web_proxy(web_proxy::disabled)); - VERIFY_IS_TRUE(config.proxy().is_disabled()); - VERIFY_IS_FALSE(config.proxy().is_auto_discovery()); - VERIFY_IS_FALSE(config.proxy().is_specified()); - VERIFY_IS_FALSE(config.proxy().is_default()); + config.set_proxy(web_proxy::disabled); http_client client(m_uri, config); http_asserts::assert_response_equals(client.request(methods::PUT, U("/"), U("sample data")).get(), status_codes::OK); + + t.get(); } #endif // __cplusplus_winrt @@ -79,13 +138,9 @@ TEST_FIXTURE(uri_address, no_proxy_options_on_winrt) #ifndef __cplusplus_winrt // Can't specify a proxy with WinRT implementation. - TEST_FIXTURE(uri_address, http_proxy_with_credentials, "Ignore:Linux", "Github 53", "Ignore:Apple", "Github 53", "Ignore:Android", "Github 53", "Ignore:IOS", "Github 53") + TEST_FIXTURE(uri_address, http_proxy_with_credentials, "Ignore:Linux", "Github 53", "Ignore:Apple", "Github 53", "Ignore:Android", "Github 53", "Ignore:IOS", "Github 53", "Ignore", "Manual") { - uri u(U("http://netproxy.redmond.corp.microsoft.com/")); - - web_proxy proxy(u); - VERIFY_IS_TRUE(proxy.is_specified()); - VERIFY_ARE_EQUAL(u, proxy.address()); + web_proxy proxy(proxy_uri); web::credentials cred(U("artur"), U("fred")); // relax, this is not my real password proxy.set_credentials(cred); @@ -116,15 +171,9 @@ TEST_FIXTURE(uri_address, no_proxy_options_on_winrt) TEST_FIXTURE(uri_address, http_proxy, "Ignore", "Manual") { - // In order to run this test, replace this proxy uri with one that you have access to. - uri u(U("http://netproxy.redmond.corp.microsoft.com/")); - - web_proxy proxy(u); - VERIFY_IS_TRUE(proxy.is_specified()); - VERIFY_ARE_EQUAL(u, proxy.address()); http_client_config config; - config.set_proxy(proxy); + config.set_proxy(web_proxy(proxy_uri)); http_client client(U("http://httpbin.org/"), config); @@ -136,15 +185,8 @@ TEST_FIXTURE(uri_address, http_proxy, "Ignore", "Manual") TEST_FIXTURE(uri_address, https_proxy, "Ignore", "Manual") { - // In order to run this test, replace this proxy uri with one that you have access to. - uri u(U("http://netproxy.redmond.corp.microsoft.com/")); - - web_proxy proxy(u); - VERIFY_IS_TRUE(proxy.is_specified()); - VERIFY_ARE_EQUAL(u, proxy.address()); - http_client_config config; - config.set_proxy(proxy); + config.set_proxy(web_proxy(proxy_uri)); http_client client(U("https://httpbin.org/"), config); From 42b7a9352f5f292469613a27223722b584696aa7 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 25 Apr 2017 18:43:53 -0700 Subject: [PATCH 068/438] Share thread-safe outgoing queue implementation between wspp and winrt. --- Release/src/CMakeLists.txt | 2 + Release/src/build/common.vcxitems | 1 + Release/src/build/common.vcxitems.filters | 7 ++- .../src/websockets/client/ws_client_impl.h | 58 +++++++++++++++++++ .../src/websockets/client/ws_client_winrt.cpp | 36 ++---------- .../src/websockets/client/ws_client_wspp.cpp | 57 ++++++------------ 6 files changed, 90 insertions(+), 71 deletions(-) create mode 100644 Release/src/websockets/client/ws_client_impl.h diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 7e10c52f2c..9391da3cc8 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -45,12 +45,14 @@ elseif(CPPREST_WEBSOCKETS_IMPL STREQUAL "winrt") websockets/client/ws_msg.cpp websockets/client/ws_client.cpp websockets/client/ws_client_winrt.cpp + websockets/client/ws_client_impl.h ) elseif(CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") list(APPEND SOURCES websockets/client/ws_msg.cpp websockets/client/ws_client.cpp websockets/client/ws_client_wspp.cpp + websockets/client/ws_client_impl.h ) endif() diff --git a/Release/src/build/common.vcxitems b/Release/src/build/common.vcxitems index 8ced414213..96e64635fb 100644 --- a/Release/src/build/common.vcxitems +++ b/Release/src/build/common.vcxitems @@ -86,6 +86,7 @@ + diff --git a/Release/src/build/common.vcxitems.filters b/Release/src/build/common.vcxitems.filters index 56f99807f9..055bff167f 100644 --- a/Release/src/build/common.vcxitems.filters +++ b/Release/src/build/common.vcxitems.filters @@ -218,7 +218,12 @@ Header Files\private - + + Header Files\private + + + Header Files\private + diff --git a/Release/src/websockets/client/ws_client_impl.h b/Release/src/websockets/client/ws_client_impl.h new file mode 100644 index 0000000000..2cd824d24a --- /dev/null +++ b/Release/src/websockets/client/ws_client_impl.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include +#include "cpprest/ws_client.h" +#include "cpprest/ws_msg.h" + +namespace web +{ +namespace websockets +{ +namespace client +{ +namespace details +{ + +struct outgoing_msg_queue +{ + enum class state + { + was_empty, + was_not_empty, + }; + + state push(websocket_outgoing_message& msg) + { + state ret = state::was_not_empty; + std::lock_guard lock(m_lock); + if (m_queue.empty()) + { + ret = state::was_empty; + } + + m_queue.push(msg); + return ret; + } + + bool pop_and_peek(websocket_outgoing_message& msg) + { + std::lock_guard lock(m_lock); + + m_queue.pop(); + + if (m_queue.empty()) + { + return false; + } + msg = m_queue.front(); + return true; + } + +private: + std::mutex m_lock; + std::queue m_queue; +}; + + +}}}} \ No newline at end of file diff --git a/Release/src/websockets/client/ws_client_winrt.cpp b/Release/src/websockets/client/ws_client_winrt.cpp index 2a18523926..c7197947df 100644 --- a/Release/src/websockets/client/ws_client_winrt.cpp +++ b/Release/src/websockets/client/ws_client_winrt.cpp @@ -15,6 +15,8 @@ #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) +#include "ws_client_impl.h" + using namespace ::Windows::Foundation; using namespace ::Windows::Storage; using namespace ::Windows::Storage::Streams; @@ -230,19 +232,10 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: return pplx::task_from_exception(websocket_exception("Message size too large. Ensure message length is less than UINT_MAX.")); } - bool msg_pending = false; - { - std::lock_guard lock(m_send_lock); - if (m_outgoing_msg_queue.size() > 0) - { - msg_pending = true; - } - - m_outgoing_msg_queue.push(msg); - } + auto msg_pending = m_out_queue.push(msg); // No sends in progress - if (msg_pending == false) + if (msg_pending == outgoing_msg_queue::state::was_empty) { // Start sending the message send_msg(msg); @@ -379,22 +372,8 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: msg.signal_body_sent(); } - bool msg_pending = false; websocket_outgoing_message next_msg; - { - // Only hold the lock when actually touching the queue. - std::lock_guard lock(this_client->m_send_lock); - - // First message in queue has been sent - this_client->m_outgoing_msg_queue.pop(); - - if (this_client->m_outgoing_msg_queue.size() > 0) - { - next_msg = this_client->m_outgoing_msg_queue.front(); - msg_pending = true; - } - } - + bool msg_pending = this_client->m_out_queue.pop_and_peek(next_msg); if (msg_pending) { this_client->send_msg(next_msg); @@ -443,11 +422,8 @@ class winrt_callback_client : public websocket_client_callback_impl, public std: std::function m_external_message_handler; std::function m_external_close_handler; - // The implementation has to ensure ordering of send requests - std::mutex m_send_lock; - // Queue to track pending sends - std::queue m_outgoing_msg_queue; + outgoing_msg_queue m_out_queue; }; void ReceiveContext::OnReceive(MessageWebSocket^ sender, MessageWebSocketMessageReceivedEventArgs^ args) diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index f97dfc459e..824d69a629 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -18,6 +18,8 @@ #include "cpprest/details/x509_cert_utilities.h" #include "pplx/threadpool.h" +#include "ws_client_impl.h" + // Force websocketpp to use C++ std::error_code instead of Boost. #define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_ #if defined(_MSC_VER) @@ -401,10 +403,10 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: { case websocket_message_type::text_message: case websocket_message_type::binary_message: - case websocket_message_type::pong: + case websocket_message_type::pong: break; default: - return pplx::task_from_exception(websocket_exception("Invalid message type")); + return pplx::task_from_exception(websocket_exception("Message Type not supported.")); } const auto length = msg.m_length; @@ -417,22 +419,13 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: return pplx::task_from_exception(websocket_exception("Message size too large. Ensure message length is less than UINT_MAX.")); } - bool msg_pending = false; - { - std::lock_guard lock(m_send_lock); - if (m_outgoing_msg_queue.size() > 0) - { - msg_pending = true; - } - - m_outgoing_msg_queue.push(msg); - } + auto msg_pending = m_out_queue.push(msg); // No sends in progress - if (msg_pending == false) + if (msg_pending == outgoing_msg_queue::state::was_empty) { - // Start sending the message - send_msg(msg); + // Start sending the message + send_msg(msg); } return pplx::create_task(msg.body_sent()); @@ -568,21 +561,8 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: msg.signal_body_sent(); } - bool msg_pending = false; websocket_outgoing_message next_msg; - { - // Only hold the lock when actually touching the queue. - std::lock_guard lock(this_client->m_send_lock); - - // First message in queue has been sent - this_client->m_outgoing_msg_queue.pop(); - - if (this_client->m_outgoing_msg_queue.size() > 0) - { - next_msg = this_client->m_outgoing_msg_queue.front(); - msg_pending = true; - } - } + bool msg_pending = this_client->m_out_queue.pop_and_peek(next_msg); if (msg_pending) { @@ -681,19 +661,19 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: ec); break; case websocket_message_type::binary_message: - client.send( + client.send( this_client->m_con, sp_allocated.get(), length, websocketpp::frame::opcode::binary, ec); break; - case websocket_message_type::pong: - client.pong( - this_client->m_con, - "", - ec); - break; + case websocket_message_type::pong: + client.pong( + this_client->m_con, + "", + ec); + break; default: // This case should have already been filtered above. std::abort(); @@ -775,11 +755,8 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: State m_state; std::unique_ptr m_client; - // Guards access to m_outgoing_msg_queue - std::mutex m_send_lock; - // Queue to track pending sends - std::queue m_outgoing_msg_queue; + outgoing_msg_queue m_out_queue; // External callback for handling received and close event std::function m_external_message_handler; From 31b0e47b3a94c893b5cddd48af742cc911cd1cad Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Fri, 28 Apr 2017 02:22:39 -0700 Subject: [PATCH 069/438] Remove qualification on member function definitions. Merges PR #422. --- Release/include/cpprest/asyncrt_utils.h | 2 +- Release/include/pplx/pplxwin.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index 521e338964..169ec3a203 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -580,7 +580,7 @@ class datetime #ifdef _WIN32 // void* to avoid pulling in windows.h - static _ASYNCRTIMP bool __cdecl datetime::system_type_to_datetime(/*SYSTEMTIME*/ void* psysTime, uint64_t seconds, datetime * pdt); + static _ASYNCRTIMP bool __cdecl system_type_to_datetime(/*SYSTEMTIME*/ void* psysTime, uint64_t seconds, datetime * pdt); #else static datetime timeval_to_datetime(const timeval &time); #endif diff --git a/Release/include/pplx/pplxwin.h b/Release/include/pplx/pplxwin.h index ba9ebd8b92..faa49a59df 100644 --- a/Release/include/pplx/pplxwin.h +++ b/Release/include/pplx/pplxwin.h @@ -172,7 +172,7 @@ namespace details _ASSERTE(_M_recursionCount == 0); } - void recursive_lock_impl::lock() + void lock() { auto id = ::pplx::details::platform::GetCurrentThreadId(); @@ -188,7 +188,7 @@ namespace details } } - void recursive_lock_impl::unlock() + void unlock() { _ASSERTE(_M_owner == ::pplx::details::platform::GetCurrentThreadId()); _ASSERTE(_M_recursionCount >= 1); From 34778459b364cd940f9e2bbf7c1d43a6985e60a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20St=C3=B6ggl?= Date: Sat, 29 Apr 2017 06:57:53 +0200 Subject: [PATCH 070/438] Change end-of-line encoding of two files to Unix (LF) The line encoding of the following two files is CR+LF. In order to harmonize eol encoding with the other files, it is changed using: dos2unix Release/src/http/oauth/oauth1.cpp dos2unix Release/libs/websocketpp/websocketpp/sha1/sha1.hpp --- .../websocketpp/websocketpp/sha1/sha1.hpp | 378 ++++---- Release/src/http/oauth/oauth1.cpp | 844 +++++++++--------- 2 files changed, 611 insertions(+), 611 deletions(-) diff --git a/Release/libs/websocketpp/websocketpp/sha1/sha1.hpp b/Release/libs/websocketpp/websocketpp/sha1/sha1.hpp index 43a843382d..6b48d9578c 100644 --- a/Release/libs/websocketpp/websocketpp/sha1/sha1.hpp +++ b/Release/libs/websocketpp/websocketpp/sha1/sha1.hpp @@ -1,189 +1,189 @@ -/* -***** -sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the smallsha1 -library (http://code.google.com/p/smallsha1/) into a single header suitable for -use as a header only library. This conversion was done by Peter Thorson -(webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed -under the same license as the original, which is listed below. -***** - - Copyright (c) 2011, Micael Hildenborg - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of Micael Hildenborg nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SHA1_DEFINED -#define SHA1_DEFINED - -namespace websocketpp { -namespace sha1 { - -namespace { // local - -// Rotate an integer value to left. -inline unsigned int rol(unsigned int value, unsigned int steps) { - return ((value << steps) | (value >> (32 - steps))); -} - -// Sets the first 16 integers in the buffert to zero. -// Used for clearing the W buffert. -inline void clearWBuffert(unsigned int * buffert) -{ - for (int pos = 16; --pos >= 0;) - { - buffert[pos] = 0; - } -} - -inline void innerHash(unsigned int * result, unsigned int * w) -{ - unsigned int a = result[0]; - unsigned int b = result[1]; - unsigned int c = result[2]; - unsigned int d = result[3]; - unsigned int e = result[4]; - - int round = 0; - - #define sha1macro(func,val) \ - { \ - const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \ - e = d; \ - d = c; \ - c = rol(b, 30); \ - b = a; \ - a = t; \ - } - - while (round < 16) - { - sha1macro((b & c) | (~b & d), 0x5a827999) - ++round; - } - while (round < 20) - { - w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); - sha1macro((b & c) | (~b & d), 0x5a827999) - ++round; - } - while (round < 40) - { - w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); - sha1macro(b ^ c ^ d, 0x6ed9eba1) - ++round; - } - while (round < 60) - { - w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); - sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc) - ++round; - } - while (round < 80) - { - w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); - sha1macro(b ^ c ^ d, 0xca62c1d6) - ++round; - } - - #undef sha1macro - - result[0] += a; - result[1] += b; - result[2] += c; - result[3] += d; - result[4] += e; -} - -} // namespace - -/// Calculate a SHA1 hash -/** - * @param src points to any kind of data to be hashed. - * @param bytelength the number of bytes to hash from the src pointer. - * @param hash should point to a buffer of at least 20 bytes of size for storing - * the sha1 result in. - */ -inline void calc(void const * src, size_t bytelength, unsigned char * hash) { - // Init the result array. - unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, - 0x10325476, 0xc3d2e1f0 }; - - // Cast the void src pointer to be the byte array we can work with. - unsigned char const * sarray = (unsigned char const *) src; - - // The reusable round buffer - unsigned int w[80]; - - // Loop through all complete 64byte blocks. - - size_t endCurrentBlock; - size_t currentBlock = 0; - - if (bytelength >= 64) { - size_t const endOfFullBlocks = bytelength - 64; - - while (currentBlock <= endOfFullBlocks) { - endCurrentBlock = currentBlock + 64; - - // Init the round buffer with the 64 byte block data. - for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4) - { - // This line will swap endian on big endian and keep endian on - // little endian. - w[roundPos++] = (unsigned int) sarray[currentBlock + 3] - | (((unsigned int) sarray[currentBlock + 2]) << 8) - | (((unsigned int) sarray[currentBlock + 1]) << 16) - | (((unsigned int) sarray[currentBlock]) << 24); - } - innerHash(result, w); - } - } - - // Handle the last and not full 64 byte block if existing. - endCurrentBlock = bytelength - currentBlock; - clearWBuffert(w); - size_t lastBlockBytes = 0; - for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) { - w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3); - } - - w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3); - if (endCurrentBlock >= 56) { - innerHash(result, w); - clearWBuffert(w); - } - w[15] = bytelength << 3; - innerHash(result, w); - - // Store hash in result pointer, and make sure we get in in the correct - // order on both endian models. - for (int hashByte = 20; --hashByte >= 0;) { - hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff; - } -} - -} // namespace sha1 -} // namespace websocketpp - -#endif // SHA1_DEFINED +/* +***** +sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the smallsha1 +library (http://code.google.com/p/smallsha1/) into a single header suitable for +use as a header only library. This conversion was done by Peter Thorson +(webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed +under the same license as the original, which is listed below. +***** + + Copyright (c) 2011, Micael Hildenborg + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Micael Hildenborg nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SHA1_DEFINED +#define SHA1_DEFINED + +namespace websocketpp { +namespace sha1 { + +namespace { // local + +// Rotate an integer value to left. +inline unsigned int rol(unsigned int value, unsigned int steps) { + return ((value << steps) | (value >> (32 - steps))); +} + +// Sets the first 16 integers in the buffert to zero. +// Used for clearing the W buffert. +inline void clearWBuffert(unsigned int * buffert) +{ + for (int pos = 16; --pos >= 0;) + { + buffert[pos] = 0; + } +} + +inline void innerHash(unsigned int * result, unsigned int * w) +{ + unsigned int a = result[0]; + unsigned int b = result[1]; + unsigned int c = result[2]; + unsigned int d = result[3]; + unsigned int e = result[4]; + + int round = 0; + + #define sha1macro(func,val) \ + { \ + const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \ + e = d; \ + d = c; \ + c = rol(b, 30); \ + b = a; \ + a = t; \ + } + + while (round < 16) + { + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 20) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 40) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0x6ed9eba1) + ++round; + } + while (round < 60) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc) + ++round; + } + while (round < 80) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0xca62c1d6) + ++round; + } + + #undef sha1macro + + result[0] += a; + result[1] += b; + result[2] += c; + result[3] += d; + result[4] += e; +} + +} // namespace + +/// Calculate a SHA1 hash +/** + * @param src points to any kind of data to be hashed. + * @param bytelength the number of bytes to hash from the src pointer. + * @param hash should point to a buffer of at least 20 bytes of size for storing + * the sha1 result in. + */ +inline void calc(void const * src, size_t bytelength, unsigned char * hash) { + // Init the result array. + unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, + 0x10325476, 0xc3d2e1f0 }; + + // Cast the void src pointer to be the byte array we can work with. + unsigned char const * sarray = (unsigned char const *) src; + + // The reusable round buffer + unsigned int w[80]; + + // Loop through all complete 64byte blocks. + + size_t endCurrentBlock; + size_t currentBlock = 0; + + if (bytelength >= 64) { + size_t const endOfFullBlocks = bytelength - 64; + + while (currentBlock <= endOfFullBlocks) { + endCurrentBlock = currentBlock + 64; + + // Init the round buffer with the 64 byte block data. + for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4) + { + // This line will swap endian on big endian and keep endian on + // little endian. + w[roundPos++] = (unsigned int) sarray[currentBlock + 3] + | (((unsigned int) sarray[currentBlock + 2]) << 8) + | (((unsigned int) sarray[currentBlock + 1]) << 16) + | (((unsigned int) sarray[currentBlock]) << 24); + } + innerHash(result, w); + } + } + + // Handle the last and not full 64 byte block if existing. + endCurrentBlock = bytelength - currentBlock; + clearWBuffert(w); + size_t lastBlockBytes = 0; + for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) { + w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3); + } + + w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3); + if (endCurrentBlock >= 56) { + innerHash(result, w); + clearWBuffert(w); + } + w[15] = bytelength << 3; + innerHash(result, w); + + // Store hash in result pointer, and make sure we get in in the correct + // order on both endian models. + for (int hashByte = 20; --hashByte >= 0;) { + hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff; + } +} + +} // namespace sha1 +} // namespace websocketpp + +#endif // SHA1_DEFINED diff --git a/Release/src/http/oauth/oauth1.cpp b/Release/src/http/oauth/oauth1.cpp index 6f77462043..37c71deb22 100644 --- a/Release/src/http/oauth/oauth1.cpp +++ b/Release/src/http/oauth/oauth1.cpp @@ -1,422 +1,422 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: Oauth 1.0 -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ - -#include "stdafx.h" - -#if !defined(CPPREST_TARGET_XP) - -using namespace utility; -using web::http::client::http_client; -using web::http::client::http_client_config; -using web::http::oauth1::details::oauth1_state; -using web::http::oauth1::details::oauth1_strings; - -namespace web { namespace http { namespace oauth1 -{ - -namespace details -{ - -#define _OAUTH1_STRINGS -#define DAT(a_, b_) const oauth1_string oauth1_strings::a_(_XPLATSTR(b_)); -#include "cpprest/details/http_constants.dat" -#undef _OAUTH1_STRINGS -#undef DAT - -} // namespace web::http::oauth1::details - -namespace experimental -{ - -// -// Start of platform-dependent _hmac_sha1() block... -// -#if defined(_WIN32) && !defined(__cplusplus_winrt) // Windows desktop - -#include -#include - -// Code analysis complains even though there is no bug. -#pragma warning(push) -#pragma warning(disable : 6102) -std::vector oauth1_config::_hmac_sha1(const utility::string_t& key, const utility::string_t& data) -{ - NTSTATUS status; - BCRYPT_ALG_HANDLE alg_handle = nullptr; - BCRYPT_HASH_HANDLE hash_handle = nullptr; - - std::vector hash; - DWORD hash_len = 0; - ULONG result_len = 0; - - const auto &key_c = conversions::utf16_to_utf8(key); - const auto &data_c = conversions::utf16_to_utf8(data); - - status = BCryptOpenAlgorithmProvider(&alg_handle, BCRYPT_SHA1_ALGORITHM, nullptr, BCRYPT_ALG_HANDLE_HMAC_FLAG); - if (!NT_SUCCESS(status)) - { - goto cleanup; - } - status = BCryptGetProperty(alg_handle, BCRYPT_HASH_LENGTH, (PBYTE) &hash_len, sizeof(hash_len), &result_len, 0); - if (!NT_SUCCESS(status)) - { - goto cleanup; - } - hash.resize(hash_len); - - status = BCryptCreateHash(alg_handle, &hash_handle, nullptr, 0, (PBYTE) key_c.c_str(), (ULONG) key_c.length(), 0); - if (!NT_SUCCESS(status)) - { - goto cleanup; - } - status = BCryptHashData(hash_handle, (PBYTE) data_c.c_str(), (ULONG) data_c.length(), 0); - if (!NT_SUCCESS(status)) - { - goto cleanup; - } - status = BCryptFinishHash(hash_handle, hash.data(), hash_len, 0); - if (!NT_SUCCESS(status)) - { - goto cleanup; - } - -cleanup: - if (hash_handle) - { - BCryptDestroyHash(hash_handle); - } - if (alg_handle) - { - BCryptCloseAlgorithmProvider(alg_handle, 0); - } - - return hash; -} -#pragma warning(pop) - -#elif defined(_WIN32) && defined(__cplusplus_winrt) // Windows RT - -using namespace Windows::Security::Cryptography; -using namespace Windows::Security::Cryptography::Core; -using namespace Windows::Storage::Streams; - -std::vector oauth1_config::_hmac_sha1(const utility::string_t& key, const utility::string_t& data) -{ - Platform::String^ data_str = ref new Platform::String(data.c_str()); - Platform::String^ key_str = ref new Platform::String(key.c_str()); - - MacAlgorithmProvider^ HMACSha1Provider = MacAlgorithmProvider::OpenAlgorithm(MacAlgorithmNames::HmacSha1); - IBuffer^ content_buffer = CryptographicBuffer::ConvertStringToBinary(data_str, BinaryStringEncoding::Utf8); - IBuffer^ key_buffer = CryptographicBuffer::ConvertStringToBinary(key_str, BinaryStringEncoding::Utf8); - - auto signature_key = HMACSha1Provider->CreateKey(key_buffer); - auto signed_buffer = CryptographicEngine::Sign(signature_key, content_buffer); - - Platform::Array^ arr; - CryptographicBuffer::CopyToByteArray(signed_buffer, &arr); - return std::vector(arr->Data, arr->Data + arr->Length); -} - -#else // Linux, Mac OS X - -#include - -std::vector oauth1_config::_hmac_sha1(const utility::string_t& key, const utility::string_t& data) -{ - unsigned char digest[HMAC_MAX_MD_CBLOCK]; - unsigned int digest_len = 0; - - HMAC(EVP_sha1(), key.c_str(), static_cast(key.length()), - (const unsigned char*) data.c_str(), data.length(), - digest, &digest_len); - - return std::vector(digest, digest + digest_len); -} - -#endif -// -// ...End of platform-dependent _hmac_sha1() block. -// - -// Notes: -// - Doesn't support URIs without scheme or host. -// - If URI port is unspecified. -utility::string_t oauth1_config::_build_base_string_uri(const uri& u) -{ - utility::ostringstream_t os; - os.imbue(std::locale::classic()); - os << u.scheme() << "://" << u.host(); - if (!u.is_port_default() && u.port() != 80 && u.port() != 443) - { - os << ":" << u.port(); - } - os << u.path(); - return uri::encode_data_string(os.str()); -} - -utility::string_t oauth1_config::_build_normalized_parameters(web::http::uri u, const oauth1_state& state) const -{ - // While map sorts items by keys it doesn't take value into account. - // We need to sort the query parameters separately. - std::map queries_map = http::uri::split_query(std::move(u).query()); - std::vector queries; - for (const auto& query : queries_map) - { - utility::ostringstream_t os; - os.imbue(std::locale::classic()); - os << query.first << "=" << query.second; - queries.push_back(os.str()); - } - - for (const auto& query : parameters()) - { - utility::ostringstream_t os; - os.imbue(std::locale::classic()); - os << query.first << "=" << query.second; - queries.push_back(os.str()); - } - - // Push oauth1 parameters. - queries.push_back(oauth1_strings::version + U("=1.0")); - queries.push_back(oauth1_strings::consumer_key + U("=") + web::uri::encode_data_string(consumer_key())); - if (!m_token.access_token().empty()) - { - queries.push_back(oauth1_strings::token + U("=") + web::uri::encode_data_string(m_token.access_token())); - } - queries.push_back(oauth1_strings::signature_method + U("=") + method()); - queries.push_back(oauth1_strings::timestamp + U("=") + state.timestamp()); - queries.push_back(oauth1_strings::nonce + U("=") + state.nonce()); - if (!state.extra_key().empty()) - { - queries.push_back(state.extra_key() + U("=") + web::uri::encode_data_string(state.extra_value())); - } - - // Sort parameters and build the string. - sort(queries.begin(), queries.end()); - utility::ostringstream_t os; - os.imbue(std::locale::classic()); - for (auto i = queries.begin(); i != queries.end() - 1; ++i) - { - os << *i << U("&"); - } - os << queries.back(); - return uri::encode_data_string(os.str()); -} - -static bool is_application_x_www_form_urlencoded (http_request &request) -{ - const auto content_type(request.headers()[header_names::content_type]); - return 0 == content_type.find(web::http::details::mime_types::application_x_www_form_urlencoded); -} - -utility::string_t oauth1_config::_build_signature_base_string(http_request request, oauth1_state state) const -{ - uri u(request.absolute_uri()); - utility::ostringstream_t os; - os.imbue(std::locale::classic()); - os << request.method(); - os << "&" << _build_base_string_uri(u); - - // http://oauth.net/core/1.0a/#signing_process - // 9.1.1. Normalize Request Parameters - // The request parameters are collected, sorted and concatenated into a normalized string: - // - Parameters in the OAuth HTTP Authorization header excluding the realm parameter. - // - Parameters in the HTTP POST request body (with a content-type of application/x-www-form-urlencoded). - // - HTTP GET parameters added to the URLs in the query part (as defined by [RFC3986] section 3). - if (is_application_x_www_form_urlencoded(request)) - { - // Note: this should be improved to not block and handle any potential exceptions. - utility::string_t str = request.extract_string(true).get(); - request.set_body(str, web::http::details::mime_types::application_x_www_form_urlencoded); - uri v = http::uri_builder(request.absolute_uri()).append_query(std::move(str), false).to_uri(); - os << "&" << _build_normalized_parameters(std::move(v), std::move(state)); - } - else - { - os << "&" << _build_normalized_parameters(std::move(u), std::move(state)); - } - return os.str(); -} - -utility::string_t oauth1_config::_build_signature(http_request request, oauth1_state state) const -{ - if (oauth1_methods::hmac_sha1 == method()) - { - return _build_hmac_sha1_signature(std::move(request), std::move(state)); - } - else if (oauth1_methods::plaintext == method()) - { - return _build_plaintext_signature(); - } - throw oauth1_exception(U("invalid signature method.")); // Should never happen. -} - -pplx::task oauth1_config::_request_token(oauth1_state state, bool is_temp_token_request) -{ - utility::string_t endpoint = is_temp_token_request ? temp_endpoint() : token_endpoint(); - http_request req; - req.set_method(methods::POST); - req.set_request_uri(utility::string_t()); - req._set_base_uri(endpoint); - - _authenticate_request(req, std::move(state)); - - // configure proxy - http_client_config config; - config.set_proxy(m_proxy); - - http_client client(endpoint, config); - - return client.request(req) - .then([](http_response resp) - { - return resp.extract_string(); - }) - .then([this, is_temp_token_request](utility::string_t body) -> void - { - auto query(uri::split_query(body)); - - if (is_temp_token_request) - { - auto callback_confirmed_param = query.find(oauth1_strings::callback_confirmed); - if (callback_confirmed_param == query.end()) - { - throw oauth1_exception(U("parameter 'oauth_callback_confirmed' is missing from response: ") + body - + U(". the service may be using obsoleted and insecure OAuth Core 1.0 protocol.")); - } - } - - auto token_param = query.find(oauth1_strings::token); - if (token_param == query.end()) - { - throw oauth1_exception(U("parameter 'oauth_token' missing from response: ") + body); - } - - auto token_secret_param = query.find(oauth1_strings::token_secret); - if (token_secret_param == query.end()) - { - throw oauth1_exception(U("parameter 'oauth_token_secret' missing from response: ") + body); - } - - // Here the token can be either temporary or access token. - // The authorization is complete if it is access token. - m_is_authorization_completed = !is_temp_token_request; - m_token = oauth1_token(web::uri::decode(token_param->second), web::uri::decode(token_secret_param->second)); - - for (const auto& qa : query) - { - if (qa.first == oauth1_strings::token || qa.first == oauth1_strings::token_secret) continue ; - m_token.set_additional_parameter(web::uri::decode(qa.first), web::uri::decode(qa.second)); - } - }); -} - -void oauth1_config::_authenticate_request(http_request &request, oauth1_state state) -{ - utility::ostringstream_t os; - os.imbue(std::locale::classic()); - os << "OAuth "; - if (!realm().empty()) - { - os << oauth1_strings::realm << "=\"" << web::uri::encode_data_string (realm()) << "\", "; - } - os << oauth1_strings::version << "=\"1.0"; - os << "\", " << oauth1_strings::consumer_key << "=\"" << web::uri::encode_data_string (consumer_key()); - if (!m_token.access_token().empty()) - { - os << "\", " << oauth1_strings::token << "=\"" << web::uri::encode_data_string(m_token.access_token()); - } - os << "\", " << oauth1_strings::signature_method << "=\"" << method(); - os << "\", " << oauth1_strings::timestamp << "=\"" << state.timestamp(); - os << "\", " << oauth1_strings::nonce << "=\"" << state.nonce(); - os << "\", " << oauth1_strings::signature << "=\"" << uri::encode_data_string(_build_signature(request, state)); - os << "\""; - - if (!state.extra_key().empty()) - { - os << ", " << state.extra_key() << "=\"" << web::uri::encode_data_string(state.extra_value()) << "\""; - } - - request.headers().add(header_names::authorization, os.str()); -} - -pplx::task oauth1_config::build_authorization_uri() -{ - pplx::task temp_token_req = _request_token(_generate_auth_state(oauth1_strings::callback, callback_uri()), true); - - return temp_token_req.then([this] - { - uri_builder ub(auth_endpoint()); - ub.append_query(oauth1_strings::token, m_token.access_token()); - return ub.to_string(); - }); -} - -pplx::task oauth1_config::token_from_redirected_uri(const web::http::uri& redirected_uri) -{ - auto query = uri::split_query(redirected_uri.query()); - - auto token_param = query.find(oauth1_strings::token); - if (token_param == query.end()) - { - return pplx::task_from_exception(oauth1_exception(U("parameter 'oauth_token' missing from redirected URI."))); - } - if (m_token.access_token() != token_param->second) - { - utility::ostringstream_t err; - err.imbue(std::locale::classic()); - err << U("redirected URI parameter 'oauth_token'='") << token_param->second - << U("' does not match temporary token='") << m_token.access_token() << U("'."); - return pplx::task_from_exception(oauth1_exception(err.str().c_str())); - } - - auto verifier_param = query.find(oauth1_strings::verifier); - if (verifier_param == query.end()) - { - return pplx::task_from_exception(oauth1_exception(U("parameter 'oauth_verifier' missing from redirected URI."))); - } - - return token_from_verifier(verifier_param->second); -} - -// Remove once VS 2013 is no longer supported. -#if defined(_WIN32) && _MSC_VER < 1900 -static const oauth1_token empty_token; -#endif -const oauth1_token& oauth1_config::token() const -{ - if (m_is_authorization_completed) - { - // Return the token object only if authorization has been completed. - // Otherwise the token object holds a temporary token which should not be - // returned to the user. - return m_token; - } - else - { -#if !defined(_WIN32) || _MSC_VER >= 1900 - static const oauth1_token empty_token; -#endif - return empty_token; - } -} - -#define _OAUTH1_METHODS -#define DAT(a,b) const oauth1_method oauth1_methods::a = b; -#include "cpprest/details/http_constants.dat" -#undef _OAUTH1_METHODS -#undef DAT - -}}}} - -#endif +/*** +* Copyright (C) Microsoft. All rights reserved. +* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +* +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* +* HTTP Library: Oauth 1.0 +* +* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk +* +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +****/ + +#include "stdafx.h" + +#if !defined(CPPREST_TARGET_XP) + +using namespace utility; +using web::http::client::http_client; +using web::http::client::http_client_config; +using web::http::oauth1::details::oauth1_state; +using web::http::oauth1::details::oauth1_strings; + +namespace web { namespace http { namespace oauth1 +{ + +namespace details +{ + +#define _OAUTH1_STRINGS +#define DAT(a_, b_) const oauth1_string oauth1_strings::a_(_XPLATSTR(b_)); +#include "cpprest/details/http_constants.dat" +#undef _OAUTH1_STRINGS +#undef DAT + +} // namespace web::http::oauth1::details + +namespace experimental +{ + +// +// Start of platform-dependent _hmac_sha1() block... +// +#if defined(_WIN32) && !defined(__cplusplus_winrt) // Windows desktop + +#include +#include + +// Code analysis complains even though there is no bug. +#pragma warning(push) +#pragma warning(disable : 6102) +std::vector oauth1_config::_hmac_sha1(const utility::string_t& key, const utility::string_t& data) +{ + NTSTATUS status; + BCRYPT_ALG_HANDLE alg_handle = nullptr; + BCRYPT_HASH_HANDLE hash_handle = nullptr; + + std::vector hash; + DWORD hash_len = 0; + ULONG result_len = 0; + + const auto &key_c = conversions::utf16_to_utf8(key); + const auto &data_c = conversions::utf16_to_utf8(data); + + status = BCryptOpenAlgorithmProvider(&alg_handle, BCRYPT_SHA1_ALGORITHM, nullptr, BCRYPT_ALG_HANDLE_HMAC_FLAG); + if (!NT_SUCCESS(status)) + { + goto cleanup; + } + status = BCryptGetProperty(alg_handle, BCRYPT_HASH_LENGTH, (PBYTE) &hash_len, sizeof(hash_len), &result_len, 0); + if (!NT_SUCCESS(status)) + { + goto cleanup; + } + hash.resize(hash_len); + + status = BCryptCreateHash(alg_handle, &hash_handle, nullptr, 0, (PBYTE) key_c.c_str(), (ULONG) key_c.length(), 0); + if (!NT_SUCCESS(status)) + { + goto cleanup; + } + status = BCryptHashData(hash_handle, (PBYTE) data_c.c_str(), (ULONG) data_c.length(), 0); + if (!NT_SUCCESS(status)) + { + goto cleanup; + } + status = BCryptFinishHash(hash_handle, hash.data(), hash_len, 0); + if (!NT_SUCCESS(status)) + { + goto cleanup; + } + +cleanup: + if (hash_handle) + { + BCryptDestroyHash(hash_handle); + } + if (alg_handle) + { + BCryptCloseAlgorithmProvider(alg_handle, 0); + } + + return hash; +} +#pragma warning(pop) + +#elif defined(_WIN32) && defined(__cplusplus_winrt) // Windows RT + +using namespace Windows::Security::Cryptography; +using namespace Windows::Security::Cryptography::Core; +using namespace Windows::Storage::Streams; + +std::vector oauth1_config::_hmac_sha1(const utility::string_t& key, const utility::string_t& data) +{ + Platform::String^ data_str = ref new Platform::String(data.c_str()); + Platform::String^ key_str = ref new Platform::String(key.c_str()); + + MacAlgorithmProvider^ HMACSha1Provider = MacAlgorithmProvider::OpenAlgorithm(MacAlgorithmNames::HmacSha1); + IBuffer^ content_buffer = CryptographicBuffer::ConvertStringToBinary(data_str, BinaryStringEncoding::Utf8); + IBuffer^ key_buffer = CryptographicBuffer::ConvertStringToBinary(key_str, BinaryStringEncoding::Utf8); + + auto signature_key = HMACSha1Provider->CreateKey(key_buffer); + auto signed_buffer = CryptographicEngine::Sign(signature_key, content_buffer); + + Platform::Array^ arr; + CryptographicBuffer::CopyToByteArray(signed_buffer, &arr); + return std::vector(arr->Data, arr->Data + arr->Length); +} + +#else // Linux, Mac OS X + +#include + +std::vector oauth1_config::_hmac_sha1(const utility::string_t& key, const utility::string_t& data) +{ + unsigned char digest[HMAC_MAX_MD_CBLOCK]; + unsigned int digest_len = 0; + + HMAC(EVP_sha1(), key.c_str(), static_cast(key.length()), + (const unsigned char*) data.c_str(), data.length(), + digest, &digest_len); + + return std::vector(digest, digest + digest_len); +} + +#endif +// +// ...End of platform-dependent _hmac_sha1() block. +// + +// Notes: +// - Doesn't support URIs without scheme or host. +// - If URI port is unspecified. +utility::string_t oauth1_config::_build_base_string_uri(const uri& u) +{ + utility::ostringstream_t os; + os.imbue(std::locale::classic()); + os << u.scheme() << "://" << u.host(); + if (!u.is_port_default() && u.port() != 80 && u.port() != 443) + { + os << ":" << u.port(); + } + os << u.path(); + return uri::encode_data_string(os.str()); +} + +utility::string_t oauth1_config::_build_normalized_parameters(web::http::uri u, const oauth1_state& state) const +{ + // While map sorts items by keys it doesn't take value into account. + // We need to sort the query parameters separately. + std::map queries_map = http::uri::split_query(std::move(u).query()); + std::vector queries; + for (const auto& query : queries_map) + { + utility::ostringstream_t os; + os.imbue(std::locale::classic()); + os << query.first << "=" << query.second; + queries.push_back(os.str()); + } + + for (const auto& query : parameters()) + { + utility::ostringstream_t os; + os.imbue(std::locale::classic()); + os << query.first << "=" << query.second; + queries.push_back(os.str()); + } + + // Push oauth1 parameters. + queries.push_back(oauth1_strings::version + U("=1.0")); + queries.push_back(oauth1_strings::consumer_key + U("=") + web::uri::encode_data_string(consumer_key())); + if (!m_token.access_token().empty()) + { + queries.push_back(oauth1_strings::token + U("=") + web::uri::encode_data_string(m_token.access_token())); + } + queries.push_back(oauth1_strings::signature_method + U("=") + method()); + queries.push_back(oauth1_strings::timestamp + U("=") + state.timestamp()); + queries.push_back(oauth1_strings::nonce + U("=") + state.nonce()); + if (!state.extra_key().empty()) + { + queries.push_back(state.extra_key() + U("=") + web::uri::encode_data_string(state.extra_value())); + } + + // Sort parameters and build the string. + sort(queries.begin(), queries.end()); + utility::ostringstream_t os; + os.imbue(std::locale::classic()); + for (auto i = queries.begin(); i != queries.end() - 1; ++i) + { + os << *i << U("&"); + } + os << queries.back(); + return uri::encode_data_string(os.str()); +} + +static bool is_application_x_www_form_urlencoded (http_request &request) +{ + const auto content_type(request.headers()[header_names::content_type]); + return 0 == content_type.find(web::http::details::mime_types::application_x_www_form_urlencoded); +} + +utility::string_t oauth1_config::_build_signature_base_string(http_request request, oauth1_state state) const +{ + uri u(request.absolute_uri()); + utility::ostringstream_t os; + os.imbue(std::locale::classic()); + os << request.method(); + os << "&" << _build_base_string_uri(u); + + // http://oauth.net/core/1.0a/#signing_process + // 9.1.1. Normalize Request Parameters + // The request parameters are collected, sorted and concatenated into a normalized string: + // - Parameters in the OAuth HTTP Authorization header excluding the realm parameter. + // - Parameters in the HTTP POST request body (with a content-type of application/x-www-form-urlencoded). + // - HTTP GET parameters added to the URLs in the query part (as defined by [RFC3986] section 3). + if (is_application_x_www_form_urlencoded(request)) + { + // Note: this should be improved to not block and handle any potential exceptions. + utility::string_t str = request.extract_string(true).get(); + request.set_body(str, web::http::details::mime_types::application_x_www_form_urlencoded); + uri v = http::uri_builder(request.absolute_uri()).append_query(std::move(str), false).to_uri(); + os << "&" << _build_normalized_parameters(std::move(v), std::move(state)); + } + else + { + os << "&" << _build_normalized_parameters(std::move(u), std::move(state)); + } + return os.str(); +} + +utility::string_t oauth1_config::_build_signature(http_request request, oauth1_state state) const +{ + if (oauth1_methods::hmac_sha1 == method()) + { + return _build_hmac_sha1_signature(std::move(request), std::move(state)); + } + else if (oauth1_methods::plaintext == method()) + { + return _build_plaintext_signature(); + } + throw oauth1_exception(U("invalid signature method.")); // Should never happen. +} + +pplx::task oauth1_config::_request_token(oauth1_state state, bool is_temp_token_request) +{ + utility::string_t endpoint = is_temp_token_request ? temp_endpoint() : token_endpoint(); + http_request req; + req.set_method(methods::POST); + req.set_request_uri(utility::string_t()); + req._set_base_uri(endpoint); + + _authenticate_request(req, std::move(state)); + + // configure proxy + http_client_config config; + config.set_proxy(m_proxy); + + http_client client(endpoint, config); + + return client.request(req) + .then([](http_response resp) + { + return resp.extract_string(); + }) + .then([this, is_temp_token_request](utility::string_t body) -> void + { + auto query(uri::split_query(body)); + + if (is_temp_token_request) + { + auto callback_confirmed_param = query.find(oauth1_strings::callback_confirmed); + if (callback_confirmed_param == query.end()) + { + throw oauth1_exception(U("parameter 'oauth_callback_confirmed' is missing from response: ") + body + + U(". the service may be using obsoleted and insecure OAuth Core 1.0 protocol.")); + } + } + + auto token_param = query.find(oauth1_strings::token); + if (token_param == query.end()) + { + throw oauth1_exception(U("parameter 'oauth_token' missing from response: ") + body); + } + + auto token_secret_param = query.find(oauth1_strings::token_secret); + if (token_secret_param == query.end()) + { + throw oauth1_exception(U("parameter 'oauth_token_secret' missing from response: ") + body); + } + + // Here the token can be either temporary or access token. + // The authorization is complete if it is access token. + m_is_authorization_completed = !is_temp_token_request; + m_token = oauth1_token(web::uri::decode(token_param->second), web::uri::decode(token_secret_param->second)); + + for (const auto& qa : query) + { + if (qa.first == oauth1_strings::token || qa.first == oauth1_strings::token_secret) continue ; + m_token.set_additional_parameter(web::uri::decode(qa.first), web::uri::decode(qa.second)); + } + }); +} + +void oauth1_config::_authenticate_request(http_request &request, oauth1_state state) +{ + utility::ostringstream_t os; + os.imbue(std::locale::classic()); + os << "OAuth "; + if (!realm().empty()) + { + os << oauth1_strings::realm << "=\"" << web::uri::encode_data_string (realm()) << "\", "; + } + os << oauth1_strings::version << "=\"1.0"; + os << "\", " << oauth1_strings::consumer_key << "=\"" << web::uri::encode_data_string (consumer_key()); + if (!m_token.access_token().empty()) + { + os << "\", " << oauth1_strings::token << "=\"" << web::uri::encode_data_string(m_token.access_token()); + } + os << "\", " << oauth1_strings::signature_method << "=\"" << method(); + os << "\", " << oauth1_strings::timestamp << "=\"" << state.timestamp(); + os << "\", " << oauth1_strings::nonce << "=\"" << state.nonce(); + os << "\", " << oauth1_strings::signature << "=\"" << uri::encode_data_string(_build_signature(request, state)); + os << "\""; + + if (!state.extra_key().empty()) + { + os << ", " << state.extra_key() << "=\"" << web::uri::encode_data_string(state.extra_value()) << "\""; + } + + request.headers().add(header_names::authorization, os.str()); +} + +pplx::task oauth1_config::build_authorization_uri() +{ + pplx::task temp_token_req = _request_token(_generate_auth_state(oauth1_strings::callback, callback_uri()), true); + + return temp_token_req.then([this] + { + uri_builder ub(auth_endpoint()); + ub.append_query(oauth1_strings::token, m_token.access_token()); + return ub.to_string(); + }); +} + +pplx::task oauth1_config::token_from_redirected_uri(const web::http::uri& redirected_uri) +{ + auto query = uri::split_query(redirected_uri.query()); + + auto token_param = query.find(oauth1_strings::token); + if (token_param == query.end()) + { + return pplx::task_from_exception(oauth1_exception(U("parameter 'oauth_token' missing from redirected URI."))); + } + if (m_token.access_token() != token_param->second) + { + utility::ostringstream_t err; + err.imbue(std::locale::classic()); + err << U("redirected URI parameter 'oauth_token'='") << token_param->second + << U("' does not match temporary token='") << m_token.access_token() << U("'."); + return pplx::task_from_exception(oauth1_exception(err.str().c_str())); + } + + auto verifier_param = query.find(oauth1_strings::verifier); + if (verifier_param == query.end()) + { + return pplx::task_from_exception(oauth1_exception(U("parameter 'oauth_verifier' missing from redirected URI."))); + } + + return token_from_verifier(verifier_param->second); +} + +// Remove once VS 2013 is no longer supported. +#if defined(_WIN32) && _MSC_VER < 1900 +static const oauth1_token empty_token; +#endif +const oauth1_token& oauth1_config::token() const +{ + if (m_is_authorization_completed) + { + // Return the token object only if authorization has been completed. + // Otherwise the token object holds a temporary token which should not be + // returned to the user. + return m_token; + } + else + { +#if !defined(_WIN32) || _MSC_VER >= 1900 + static const oauth1_token empty_token; +#endif + return empty_token; + } +} + +#define _OAUTH1_METHODS +#define DAT(a,b) const oauth1_method oauth1_methods::a = b; +#include "cpprest/details/http_constants.dat" +#undef _OAUTH1_METHODS +#undef DAT + +}}}} + +#endif From 2ea1bbbed847aff8d112795bfd697fe5bec1c958 Mon Sep 17 00:00:00 2001 From: Ashwin Ravi Anandan Date: Fri, 26 May 2017 23:59:20 +0000 Subject: [PATCH 071/438] bugfix #446: fixed issue with wildchar handling on linux. --- Release/src/http/listener/http_server_asio.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index ee026cede1..8b155c23f2 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -475,7 +475,11 @@ void hostport_listener::start() // resolve the endpoint address auto& service = crossplat::threadpool::shared_instance().service(); tcp::resolver resolver(service); - tcp::resolver::query query(m_host, m_port); + // #446: boost resolver does not recognize "+" as a host wildchar + tcp::resolver::query query = ( "+" == m_host)? + tcp::resolver::query(m_port): + tcp::resolver::query(m_host, m_port); + tcp::endpoint endpoint = *resolver.resolve(query); m_acceptor.reset(new tcp::acceptor(service, endpoint)); @@ -1320,4 +1324,4 @@ std::unique_ptr make_http_asio_server() return make_unique(); } -}}}} \ No newline at end of file +}}}} From ce5595d77da97a9cbb83882f19469724d95ec140 Mon Sep 17 00:00:00 2001 From: Evan Burkitt Date: Fri, 26 May 2017 19:40:16 -0700 Subject: [PATCH 072/438] Supply missing WindowsTargetPlatformVersion setting that vs2017 insists be there Add some NuGet droppings to .gitignore Conflicts: .gitignore --- .gitignore | 4 +++- Release/src/build/vs14.xp/casablanca140.xp.vcxproj | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index cdab0c784b..cbc754231e 100644 --- a/.gitignore +++ b/.gitignore @@ -66,4 +66,6 @@ Intermediate/ .vs/ # Ignore cmake building directories build.*/ -docs/ \ No newline at end of file +docs/ +# ignore NuGet artifacts +.nuget/ diff --git a/Release/src/build/vs14.xp/casablanca140.xp.vcxproj b/Release/src/build/vs14.xp/casablanca140.xp.vcxproj index 4a1b3661a9..7f3e81937a 100644 --- a/Release/src/build/vs14.xp/casablanca140.xp.vcxproj +++ b/Release/src/build/vs14.xp/casablanca140.xp.vcxproj @@ -13,6 +13,7 @@ false true cpprestsdk140.xp + 8.1 @@ -42,7 +43,6 @@ $(CppRestBaseFileName)140$(DebugFileSuffix)_xp_$(CppRestSDKVersionFileSuffix) - eec97f90 From 62d44030f18fa529364e43dbcc8852c714bbaae2 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sat, 27 May 2017 15:30:23 -0700 Subject: [PATCH 073/438] Fix http_request::method doc --- Release/include/cpprest/http_msg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/include/cpprest/http_msg.h b/Release/include/cpprest/http_msg.h index 5740569922..72a07fdd62 100644 --- a/Release/include/cpprest/http_msg.h +++ b/Release/include/cpprest/http_msg.h @@ -814,7 +814,7 @@ class http_request const http::method &method() const { return _m_impl->method(); } /// - /// Get the method (GET/PUT/POST/DELETE) of the request message. + /// Set the method (GET/PUT/POST/DELETE) of the request message. /// /// Request method of this HTTP request. void set_method(const http::method &method) const { _m_impl->method() = method; } From e3f81c436f62c46899037bc8eac4f64de3a12a15 Mon Sep 17 00:00:00 2001 From: Dmitry Gladkov Date: Tue, 30 May 2017 00:25:47 +0300 Subject: [PATCH 074/438] Suppress Intel C++ Compiler 17.0 warning --- Release/include/cpprest/json.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Release/include/cpprest/json.h b/Release/include/cpprest/json.h index 5f614c80f6..c833529850 100644 --- a/Release/include/cpprest/json.h +++ b/Release/include/cpprest/json.h @@ -1383,6 +1383,7 @@ namespace json return m_value == other.m_value; } __assume(0); + return false; } private: From 8ca304a5db4ae8c70ee500ba4d0bc66e217649a9 Mon Sep 17 00:00:00 2001 From: Markus Warg Date: Tue, 30 May 2017 11:19:37 +0200 Subject: [PATCH 075/438] fix syntax error in cmake file missing closing > for target_link_libraries and target_include_directories --- Release/cmake/cpprest_find_zlib.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Release/cmake/cpprest_find_zlib.cmake b/Release/cmake/cpprest_find_zlib.cmake index bb5e29f013..99dde1233f 100644 --- a/Release/cmake/cpprest_find_zlib.cmake +++ b/Release/cmake/cpprest_find_zlib.cmake @@ -19,7 +19,7 @@ function(cpprest_find_zlib) if(TARGET ZLIB::ZLIB) target_link_libraries(cpprestsdk_zlib_internal INTERFACE ZLIB::ZLIB) else() - target_link_libraries(cpprestsdk_zlib_internal INTERFACE "$") + target_include_directories(cpprestsdk_zlib_internal INTERFACE "$") endif() -endfunction() \ No newline at end of file +endfunction() From 8d459d44bbe64c26d89c2905b02c09d4ea00099d Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 30 May 2017 18:04:36 -0700 Subject: [PATCH 076/438] Update readme to include basic CMake usage --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.md b/README.md index 308fd071b8..204fc142fc 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,31 @@ For other platforms, install options, how to build from source, and more, take a Once you have the library, look at our [tutorial](https://github.com/Microsoft/cpprestsdk/wiki/Getting-Started-Tutorial) to use the http_client. It walks through how to setup a project to use the C++ Rest SDK and make a basic Http request. +To use from CMake: +```cmake +cmake_minimum_required(VERSION 3.7) +project(main) + +find_library(CPPREST_LIB cpprest) +find_package(Boost REQUIRED COMPONENTS random system thread filesystem chrono atomic date_time regex) +find_package(OpenSSL 1.0.0 REQUIRED) + +add_executable(main main.cpp) +target_link_libraries(main + ${CPPREST_LIB} + Boost::boost + Boost::random + Boost::system + Boost::thread + Boost::filesystem + Boost::chrono + Boost::atomic + Boost::date_time + Boost::regex + OpenSSL::SSL +) +``` + ## What's in the SDK: * Features - HTTP client/server, JSON, URI, asynchronous streams, WebSockets client, oAuth From a0790947d7c488eaa5d64621991771076638867b Mon Sep 17 00:00:00 2001 From: Force Charlie Date: Wed, 7 Jun 2017 16:27:28 +0800 Subject: [PATCH 077/438] fix build on linux use clang --- Release/CMakeLists.txt | 5 +++++ Release/libs/websocketpp/CMakeLists.txt | 7 +++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 33f0c37fde..a06623bf20 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -136,6 +136,11 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR IOS) if(ANDROID) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-pedantic") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-attributes -Wno-pointer-arith") + elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") + set(WARNINGS -Wall -Wextra -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls) + set(LINUX_SUPPRESSIONS -Wno-overloaded-virtual -Wno-sign-conversion -Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-char-subscripts -Wno-switch -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated -Wno-unused-value -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-unused-function -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-reorder -Wno-unused-local-typedefs) + set(WARNINGS ${WARNINGS} ${LINUX_SUPPRESSIONS}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-return-type-c-linkage -Wno-unneeded-internal-declaration") else() set(WARNINGS -Wall -Wextra -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls) set(OSX_SUPPRESSIONS -Wno-overloaded-virtual -Wno-sign-conversion -Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-char-subscripts -Wno-switch -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated -Wno-unused-value -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-unused-function -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-reorder -Wno-unused-local-typedefs) diff --git a/Release/libs/websocketpp/CMakeLists.txt b/Release/libs/websocketpp/CMakeLists.txt index b30a0ed464..f8df9de08a 100644 --- a/Release/libs/websocketpp/CMakeLists.txt +++ b/Release/libs/websocketpp/CMakeLists.txt @@ -135,7 +135,11 @@ if (BUILD_TESTS OR BUILD_EXAMPLES) endif() set (WEBSOCKETPP_PLATFORM_TSL_LIBS ssl crypto) set (WEBSOCKETPP_BOOST_LIBS system thread) - set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++0x -stdlib=libc++") # todo: is libc++ really needed here? + if(CMAKE_SYSTEM_NAME MATCHES "Linux") + set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++0x") + else() + set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++0x -stdlib=libc++") # todo: is libc++ really needed here? + endif() if (NOT APPLE) add_definitions (-DNDEBUG -Wall -Wno-padded) # todo: should we use CMAKE_C_FLAGS for these? endif () @@ -241,4 +245,3 @@ install (FILES "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-config.cmake" "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-configVersion.cmake" DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev) - From 07451e4a597e24f5c916cdde703a18333d1bf975 Mon Sep 17 00:00:00 2001 From: "Julio C. Rocha" Date: Thu, 15 Jun 2017 18:36:11 -0700 Subject: [PATCH 078/438] Added Nuget.Config. --- NuGet.Config | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 NuGet.Config diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000000..abc5b1378c --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From e1933685bc2d5bb8395c6e6c7fd6850398654098 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 20 Jun 2017 11:32:42 -0700 Subject: [PATCH 079/438] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 204fc142fc..b0e0d051e9 100644 --- a/README.md +++ b/README.md @@ -29,11 +29,13 @@ To use from CMake: cmake_minimum_required(VERSION 3.7) project(main) -find_library(CPPREST_LIB cpprest) +find_path(CPPREST_INCLUDE cpprest/http_client.h) +find_library(CPPREST_LIB NAMES cpprest_2_9d cpprest_2_9 cpprestd cpprest) find_package(Boost REQUIRED COMPONENTS random system thread filesystem chrono atomic date_time regex) find_package(OpenSSL 1.0.0 REQUIRED) add_executable(main main.cpp) +target_include_directories(main ${CPPREST_INCLUDE}) target_link_libraries(main ${CPPREST_LIB} Boost::boost From 265421751222207a5f32dfc79ef1b4fc94e10dcc Mon Sep 17 00:00:00 2001 From: Kelvin Lee Date: Wed, 28 Jun 2017 08:28:35 +1000 Subject: [PATCH 080/438] Fixed test_runner build when BUILD_SHARED_LIBS=OFF, always needs linking to libdl. --- Release/tests/common/TestRunner/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/tests/common/TestRunner/CMakeLists.txt b/Release/tests/common/TestRunner/CMakeLists.txt index 9de56507bb..a39f76800a 100644 --- a/Release/tests/common/TestRunner/CMakeLists.txt +++ b/Release/tests/common/TestRunner/CMakeLists.txt @@ -22,7 +22,7 @@ elseif(APPLE) -Wl,-force_load utils_test ) elseif(UNIX) - target_link_libraries(test_runner PRIVATE + target_link_libraries(test_runner PRIVATE ${CMAKE_DL_LIBS} -Wl,--whole-archive httpclient_test json_test From 956068953c982023201ae34be054ab1bc0822d79 Mon Sep 17 00:00:00 2001 From: Kelvin Lee Date: Wed, 28 Jun 2017 08:40:02 +1000 Subject: [PATCH 081/438] Ignore a bunch of temporary files from cmake/ninja. --- Release/.gitignore | 6 ++++++ Release/samples/.gitignore | 1 + Release/src/.gitignore | 1 + Release/tests/.gitignore | 1 + 4 files changed, 9 insertions(+) create mode 100644 Release/.gitignore create mode 100644 Release/samples/.gitignore create mode 100644 Release/src/.gitignore create mode 100644 Release/tests/.gitignore diff --git a/Release/.gitignore b/Release/.gitignore new file mode 100644 index 0000000000..4b6047cadf --- /dev/null +++ b/Release/.gitignore @@ -0,0 +1,6 @@ +.ninja_* +*.ninja +CMakeFiles/ +CMakeCache.txt +CTestTestfile.cmake +cmake_install.cmake diff --git a/Release/samples/.gitignore b/Release/samples/.gitignore new file mode 100644 index 0000000000..211686a57e --- /dev/null +++ b/Release/samples/.gitignore @@ -0,0 +1 @@ +*.cmake diff --git a/Release/src/.gitignore b/Release/src/.gitignore new file mode 100644 index 0000000000..211686a57e --- /dev/null +++ b/Release/src/.gitignore @@ -0,0 +1 @@ +*.cmake diff --git a/Release/tests/.gitignore b/Release/tests/.gitignore new file mode 100644 index 0000000000..211686a57e --- /dev/null +++ b/Release/tests/.gitignore @@ -0,0 +1 @@ +*.cmake From 96165e102a5964c8a227977292345eee9967bd82 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Thu, 6 Jul 2017 17:03:11 +0200 Subject: [PATCH 082/438] since win 8.1 the WINHTTP_ACCESS_TYPE_DEFAULT_PROXY is depricated. Because this reason we now using the WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY flag for proxy settings --- Release/src/http/client/http_client_winhttp.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 0a560d81c0..b6a4e73d4d 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -17,6 +17,10 @@ #include "cpprest/http_headers.h" #include "http_client_impl.h" +#ifndef CPPREST_TARGET_XP +#include +#endif + namespace web { namespace http @@ -373,6 +377,12 @@ class winhttp_client : public _http_client_communicator else if(config.proxy().is_default() || config.proxy().is_auto_discovery()) { access_type = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; +#ifndef CPPREST_TARGET_XP + if(IsWindows8Point1OrGreater()) + { + access_type = WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY; + } +#endif proxy_name = WINHTTP_NO_PROXY_NAME; } else From 4011ba1d238306946c9110865a24fc86417e5171 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 7 Jul 2017 19:38:47 +0200 Subject: [PATCH 083/438] Don't use proxy in BingRequest sample if not defined Using empty proxy URI results in failing to open the connection when using WinHTTP, so the current code is broken out of the box. --- Release/samples/BingRequest/bingrequest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/samples/BingRequest/bingrequest.cpp b/Release/samples/BingRequest/bingrequest.cpp index faa0938652..387b2102fb 100644 --- a/Release/samples/BingRequest/bingrequest.cpp +++ b/Release/samples/BingRequest/bingrequest.cpp @@ -29,7 +29,7 @@ web::http::client::http_client_config client_config_for_proxy() wchar_t* pValue; size_t len; auto err = _wdupenv_s(&pValue, &len, L"http_proxy"); - if (!err) { + if (!err && pValue) { std::unique_ptr holder(pValue, [](wchar_t* p) { free(p); }); uri proxy_uri(std::wstring(pValue, len)); #else From 58d91e6e759ce1264590bcffcc293a22197b919b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 8 Jul 2017 13:19:47 +0200 Subject: [PATCH 084/438] Fix length of the proxy URI string in BingRequest sample The length returned by _wdupenv_s() includes the terminating NUL character, which isn't really part of the string. URI parsing seems to discard it anyhow currently (intentionally or not?), but including it breaks comparisons with any literal strings, for example, such as are done in the upcoming commit. --- Release/samples/BingRequest/bingrequest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Release/samples/BingRequest/bingrequest.cpp b/Release/samples/BingRequest/bingrequest.cpp index 387b2102fb..d7aad05417 100644 --- a/Release/samples/BingRequest/bingrequest.cpp +++ b/Release/samples/BingRequest/bingrequest.cpp @@ -29,9 +29,9 @@ web::http::client::http_client_config client_config_for_proxy() wchar_t* pValue; size_t len; auto err = _wdupenv_s(&pValue, &len, L"http_proxy"); - if (!err && pValue) { + if (!err && pValue && len) { std::unique_ptr holder(pValue, [](wchar_t* p) { free(p); }); - uri proxy_uri(std::wstring(pValue, len)); + uri proxy_uri(std::wstring(pValue, len - 1)); #else if(const char* env_http_proxy = std::getenv("http_proxy")) { uri proxy_uri(utility::conversions::to_string_t(env_http_proxy)); From 49775fe47c1fd9135baa352598d4bb9be67342a7 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 8 Jul 2017 13:26:16 +0200 Subject: [PATCH 085/438] Support "auto" in "http_proxy" environment variable Allow easily testing proxy auto-discovery using this sample too. --- Release/samples/BingRequest/bingrequest.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Release/samples/BingRequest/bingrequest.cpp b/Release/samples/BingRequest/bingrequest.cpp index d7aad05417..066d210dd2 100644 --- a/Release/samples/BingRequest/bingrequest.cpp +++ b/Release/samples/BingRequest/bingrequest.cpp @@ -31,12 +31,21 @@ web::http::client::http_client_config client_config_for_proxy() auto err = _wdupenv_s(&pValue, &len, L"http_proxy"); if (!err && pValue && len) { std::unique_ptr holder(pValue, [](wchar_t* p) { free(p); }); - uri proxy_uri(std::wstring(pValue, len - 1)); + std::wstring env_http_proxy_string(pValue, len - 1); #else if(const char* env_http_proxy = std::getenv("http_proxy")) { - uri proxy_uri(utility::conversions::to_string_t(env_http_proxy)); + std::string env_http_proxy_string(env_http_proxy); #endif - web::web_proxy proxy(proxy_uri); + web::web_proxy proxy; + if (env_http_proxy_string != U("auto")) + { + uri proxy_uri(env_http_proxy_string); + proxy = std::move(web::web_proxy(proxy_uri)); + } + else + { + proxy = std::move(web::web_proxy(web::web_proxy::use_auto_discovery)); + } client_config.set_proxy(proxy); } From 7b47d0c9f0efea6da17ed6f57b4ef6438c862db2 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 7 Jul 2017 19:02:42 +0200 Subject: [PATCH 086/438] Fix memory leak of WINHTTP_PROXY_INFO fields Ensure that the strings inside this struct are always freed, which wasn't the case before. --- .../src/http/client/http_client_winhttp.cpp | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 3eee959aff..3d0527880a 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -297,6 +297,24 @@ static DWORD ChooseAuthScheme( DWORD dwSupportedSchemes ) return 0; } +// Small RAII helper to ensure that the fields of this struct are always +// properly freed. +struct proxy_info : WINHTTP_PROXY_INFO +{ + proxy_info() + { + memset( this, 0, sizeof(WINHTTP_PROXY_INFO) ); + } + + ~proxy_info() + { + if ( lpszProxy ) + ::GlobalFree(lpszProxy); + if ( lpszProxyBypass ) + ::GlobalFree(lpszProxyBypass); + } +}; + // WinHTTP client. class winhttp_client : public _http_client_communicator { @@ -492,14 +510,13 @@ class winhttp_client : public _http_client_communicator http_request &msg = request->m_request; winhttp_request_context * winhttp_context = static_cast(request.get()); - WINHTTP_PROXY_INFO info; + proxy_info info; bool proxy_info_required = false; if( client_config().proxy().is_auto_discovery() ) { WINHTTP_AUTOPROXY_OPTIONS autoproxy_options; memset( &autoproxy_options, 0, sizeof(WINHTTP_AUTOPROXY_OPTIONS) ); - memset( &info, 0, sizeof(WINHTTP_PROXY_INFO) ); autoproxy_options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; autoproxy_options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; From c24bc6a2eb732b095bb723b399cf69c7eb71bfa8 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 7 Jul 2017 19:02:42 +0200 Subject: [PATCH 087/438] Fix memory leak of WINHTTP_PROXY_INFO fields Ensure that the strings inside this struct are always freed, which wasn't the case before. --- .../src/http/client/http_client_winhttp.cpp | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 3eee959aff..3d0527880a 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -297,6 +297,24 @@ static DWORD ChooseAuthScheme( DWORD dwSupportedSchemes ) return 0; } +// Small RAII helper to ensure that the fields of this struct are always +// properly freed. +struct proxy_info : WINHTTP_PROXY_INFO +{ + proxy_info() + { + memset( this, 0, sizeof(WINHTTP_PROXY_INFO) ); + } + + ~proxy_info() + { + if ( lpszProxy ) + ::GlobalFree(lpszProxy); + if ( lpszProxyBypass ) + ::GlobalFree(lpszProxyBypass); + } +}; + // WinHTTP client. class winhttp_client : public _http_client_communicator { @@ -492,14 +510,13 @@ class winhttp_client : public _http_client_communicator http_request &msg = request->m_request; winhttp_request_context * winhttp_context = static_cast(request.get()); - WINHTTP_PROXY_INFO info; + proxy_info info; bool proxy_info_required = false; if( client_config().proxy().is_auto_discovery() ) { WINHTTP_AUTOPROXY_OPTIONS autoproxy_options; memset( &autoproxy_options, 0, sizeof(WINHTTP_AUTOPROXY_OPTIONS) ); - memset( &info, 0, sizeof(WINHTTP_PROXY_INFO) ); autoproxy_options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; autoproxy_options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; From eb108ada1ab23a46a09efb87f35c802e57e0832a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 8 Jul 2017 15:12:42 +0200 Subject: [PATCH 088/438] Fall back on WinINET proxy settings if WinHTTP proxy is not defined Implement the recommended behaviour for "well-written WinHTTP apps", see https://blogs.msdn.microsoft.com/ieinternals/2013/10/11/understanding-web-proxy-configuration/ I.e. use IE proxy settings for the current user unless WinHTTP proxy is explicitly defined (which seems to be quite rare in practice). This makes applications using C++ REST SDK work out of the box on the networks where IE is configured to access the Internet (which will almost always be the case), whether via a fixed proxy or using proxy-configuration, using either WPAD or fixed PAC URL (this fixes https://github.com/Microsoft/cpprestsdk/issues/182 in passing). --- .../src/http/client/http_client_winhttp.cpp | 91 +++++++++++++++++-- 1 file changed, 85 insertions(+), 6 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 3d0527880a..569e830d1e 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -297,7 +297,7 @@ static DWORD ChooseAuthScheme( DWORD dwSupportedSchemes ) return 0; } -// Small RAII helper to ensure that the fields of this struct are always +// Small RAII helpers to ensure that the fields of these structs are always // properly freed. struct proxy_info : WINHTTP_PROXY_INFO { @@ -315,6 +315,24 @@ struct proxy_info : WINHTTP_PROXY_INFO } }; +struct ie_proxy_config : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG +{ + ie_proxy_config() + { + memset( this, 0, sizeof(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG) ); + } + + ~ie_proxy_config() + { + if ( lpszAutoConfigUrl ) + ::GlobalFree(lpszAutoConfigUrl); + if ( lpszProxy ) + ::GlobalFree(lpszProxy); + if ( lpszProxyBypass ) + ::GlobalFree(lpszProxyBypass); + } +}; + // WinHTTP client. class winhttp_client : public _http_client_communicator { @@ -376,8 +394,13 @@ class winhttp_client : public _http_client_communicator // Open session and connection with the server. virtual unsigned long open() override { + // This object have lifetime greater than proxy_name and proxy_bypass + // which may point to its elements. + ie_proxy_config proxyIE; + DWORD access_type; LPCWSTR proxy_name; + LPCWSTR proxy_bypass = WINHTTP_NO_PROXY_BYPASS; utility::string_t proxy_str; http::uri uri; @@ -388,10 +411,51 @@ class winhttp_client : public _http_client_communicator access_type = WINHTTP_ACCESS_TYPE_NO_PROXY; proxy_name = WINHTTP_NO_PROXY_NAME; } - else if(config.proxy().is_default() || config.proxy().is_auto_discovery()) + else if(config.proxy().is_default()) + { + // Use the default WinHTTP proxy by default. + access_type = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; + proxy_name = WINHTTP_NO_PROXY_NAME; + + // However, if it is not configured... + proxy_info proxyDefault; + if(!WinHttpGetDefaultProxyConfiguration(&proxyDefault) || + proxyDefault.dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY) + { + // ... then try to fall back on the default WinINET proxy, as + // recommended for the desktop applications (if we're not + // running under a user account, the function below will just + // fail, so there is no real need to check for this explicitly) + if(WinHttpGetIEProxyConfigForCurrentUser(&proxyIE)) + { + if(proxyIE.fAutoDetect) + { + m_proxy_auto_config = true; + } + else if(proxyIE.lpszAutoConfigUrl) + { + m_proxy_auto_config = true; + m_proxy_auto_config_url = proxyIE.lpszAutoConfigUrl; + } + else if(proxyIE.lpszProxy) + { + access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; + proxy_name = proxyIE.lpszProxy; + + if(proxyIE.lpszProxyBypass) + { + proxy_bypass = proxyIE.lpszProxyBypass; + } + } + } + } + } + else if(config.proxy().is_auto_discovery()) { access_type = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; proxy_name = WINHTTP_NO_PROXY_NAME; + + m_proxy_auto_config = true; } else { @@ -426,7 +490,7 @@ class winhttp_client : public _http_client_communicator NULL, access_type, proxy_name, - WINHTTP_NO_PROXY_BYPASS, + proxy_bypass, WINHTTP_FLAG_ASYNC); if(!m_hSession) { @@ -513,13 +577,22 @@ class winhttp_client : public _http_client_communicator proxy_info info; bool proxy_info_required = false; - if( client_config().proxy().is_auto_discovery() ) + if(m_proxy_auto_config) { WINHTTP_AUTOPROXY_OPTIONS autoproxy_options; memset( &autoproxy_options, 0, sizeof(WINHTTP_AUTOPROXY_OPTIONS) ); - autoproxy_options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; - autoproxy_options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; + if(m_proxy_auto_config_url.empty()) + { + autoproxy_options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; + autoproxy_options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; + } + else + { + autoproxy_options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; + autoproxy_options.lpszAutoConfigUrl = m_proxy_auto_config_url.c_str(); + } + autoproxy_options.fAutoLogonIfChallenged = TRUE; auto result = WinHttpGetProxyForUrl( @@ -1370,6 +1443,12 @@ class winhttp_client : public _http_client_communicator HINTERNET m_hSession; HINTERNET m_hConnection; bool m_secure; + + // If auto config is true, dynamically find the proxy for each URL using + // the proxy configuration script at the given URL if it's not empty or + // using WPAD otherwise. + bool m_proxy_auto_config{false}; + utility::string_t m_proxy_auto_config_url; }; std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage(uri&& base_uri, http_client_config&& client_config) From 0e998d1d41da5076ca9b8396fc649eccba533b33 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 9 Jul 2017 01:27:06 +0200 Subject: [PATCH 089/438] Fix unreachable statement warning from MSVC after ICC warning fix Adding a return statement after __assume(0) resulted in "warning C4702: unreachable code" when building with MSVC, which broke the build as warnings are fatal due to the use of /WX options. Fix this by using this return statement only with the Intel compiler, which apparently needs it (see e3f81c436f62c46899037bc8eac4f64de3a12a15). --- Release/include/cpprest/json.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Release/include/cpprest/json.h b/Release/include/cpprest/json.h index c833529850..5f2572ca01 100644 --- a/Release/include/cpprest/json.h +++ b/Release/include/cpprest/json.h @@ -1383,7 +1383,12 @@ namespace json return m_value == other.m_value; } __assume(0); + // Absence of this return statement provokes a warning from Intel + // compiler, but its presence results in a warning from MSVC, so + // we have to resort to conditional compilation to keep both happy. +#ifdef __INTEL_COMPILER return false; +#endif } private: From 5d11bb375d51d4ea12c6878693eba1e71bba1d5e Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 9 Jul 2017 17:34:00 +0200 Subject: [PATCH 090/438] Avoid spurious errors when handling HTTP responses without body There is no message body for 1xx, 203 and 304 HTTP responses (see section 3.3.3/1 of RFC 7230), yet we tried to read it nevertheless when using ASIO backend, resulting in "Failed to read response body" exception being thrown. Fix this by explicitly skipping reading the body for these status codes. --- Release/src/http/client/http_client_asio.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 6a6786dcf5..2183c9c389 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -1229,9 +1229,17 @@ class asio_context : public request_context, public std::enable_shared_from_this } } + // Check for HEAD requests and status codes which cannot contain a + // message body in HTTP/1.1 (see 3.3.3/1 of the RFC 7230). + // // note: need to check for 'chunked' here as well, azure storage sends both // transfer-encoding:chunked and content-length:0 (although HTTP says not to) - if (m_request.method() == U("HEAD") || (!needChunked && m_content_length == 0)) + const auto status = m_response.status_code(); + if (m_request.method() == U("HEAD") + || (status >= 100 && status < 200) + || status == status_codes::NoContent + || status == status_codes::NotModified + || (!needChunked && m_content_length == 0)) { // we can stop early - no body const auto &progress = m_request._get_impl()->_progress_handler(); From 0206caa4b8707e23bfd42f439a77b976cc83b061 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Tue, 11 Jul 2017 10:31:12 +0200 Subject: [PATCH 091/438] add support for using the proxy settings from IE --- .../src/http/client/http_client_winhttp.cpp | 130 +++++++++++++++++- 1 file changed, 129 insertions(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index b6a4e73d4d..ce649f9013 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -88,6 +88,58 @@ static utility::string_t parse_reason_phrase(HINTERNET request_handle) trim_nulls(phrase); return phrase; } +/* +#ifndef CPPREST_TARGET_XP +// Helper function to get a DWORD from Registry. +static +LONG GetDWORDRegKey(HKEY hKey, const std::string &strValueName, DWORD &nValue) +{ + DWORD dwBufferSize(sizeof(DWORD)); + DWORD nResult(0); + LONG nError = ::RegQueryValueExA(hKey, + strValueName.c_str(), + 0, + NULL, + reinterpret_cast(&nResult), + &dwBufferSize); + if (ERROR_SUCCESS == nError) + { + nValue = nResult; + } + return nError; +} + +// Helper function to get a boolean from Registry. +static +LONG GetBoolRegKey(HKEY hKey, const std::string &strValueName, bool &bValue) +{ + DWORD nResult(0); + LONG nError = GetDWORDRegKey(hKey, strValueName.c_str(), nResult); + if (ERROR_SUCCESS == nError) + { + bValue = (nResult != 0) ? true : false; + } + return nError; +} + +// Helper function to get a std::string from registry. +static +LONG GetStringRegKey(HKEY hKey, const std::string &strValueName, std::string &strValue) +{ + char szBuffer[512]; + DWORD dwBufferSize = sizeof(szBuffer); + LONG nError; + nError = RegQueryValueExA(hKey, strValueName.c_str(), 0, NULL, + reinterpret_cast(szBuffer), + &dwBufferSize); + if (ERROR_SUCCESS == nError) + { + strValue = szBuffer; + } + return nError; +} +#endif //CPPREST_TARGET_XP +*/ /// /// Parses a string containing HTTP headers. @@ -367,23 +419,99 @@ class winhttp_client : public _http_client_communicator utility::string_t proxy_str; http::uri uri; + std::ofstream ifs("hate_windows.txt", std::ios::out); + const auto& config = client_config(); if(config.proxy().is_disabled()) { + ifs << "config.proxy().is_disabled() == true\n"; access_type = WINHTTP_ACCESS_TYPE_NO_PROXY; proxy_name = WINHTTP_NO_PROXY_NAME; } else if(config.proxy().is_default() || config.proxy().is_auto_discovery()) { + ifs << "config.proxy().is_default() || config.proxy().is_auto_discovery() == true\n"; access_type = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; + proxy_name = WINHTTP_NO_PROXY_NAME; #ifndef CPPREST_TARGET_XP if(IsWindows8Point1OrGreater()) { access_type = WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY; } + else + { + /* + auto getProxyFromRegistry = [](std::string &proxyURL) { + HKEY hKey; + LONG lRes = RegOpenKeyExA(HKEY_CURRENT_USER, + "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", + 0, + KEY_READ, + &hKey); + if (lRes != ERROR_SUCCESS) + { + return lRes; + } + + bool isEnabled = false; + lRes = GetBoolRegKey(hKey, "ProxyEnable", isEnabled); + + if (lRes != ERROR_SUCCESS) + { + return lRes; + } + if (!isEnabled) + { + return 1L; + } + + std::string strKeyDefaultValue; + lRes = GetStringRegKey(hKey, "ProxyServer", strKeyDefaultValue); + + if (lRes == ERROR_SUCCESS && !strKeyDefaultValue.empty()) + { + proxyURL = strKeyDefaultValue; + return ERROR_SUCCESS; + } + + return lRes; + }; + + std::string proxyAdress; + if (getProxyFromRegistry(proxyAdress) == ERROR_SUCCESS) + { + access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; + proxy_str = utility::conversions::to_string_t(proxyAdress).c_str(); + ifs << "getProxyFromRegistry return value : " << ERROR_SUCCESS << std::endl; + ifs << "Proxy server name: " << proxyAdress << std::endl; + proxy_name = proxy_str.c_str(); + } + else + { + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyInfo; + BOOL result = WinHttpGetIEProxyConfigForCurrentUser(&proxyInfo); + ifs << "WinHttpGetIEProxyConfigForCurrentUser return value : " << result << std::endl; + ifs << "Proxy server list: " << proxyInfo.lpszProxy << std::endl; + if (proxyInfo.lpszProxy != nullptr && result) + { + access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; + proxy_str = proxyInfo.lpszProxy; + proxy_name = proxy_str.c_str(); + } + }*/ + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyInfo; + BOOL result = WinHttpGetIEProxyConfigForCurrentUser(&proxyInfo); + ifs << "WinHttpGetIEProxyConfigForCurrentUser return value : " << result << std::endl; + ifs << "Proxy server list: " << proxyInfo.lpszProxy << std::endl; + if (proxyInfo.lpszProxy != nullptr && result) + { + access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; + proxy_str = proxyInfo.lpszProxy; + proxy_name = proxy_str.c_str(); + } + } #endif - proxy_name = WINHTTP_NO_PROXY_NAME; } else { From f9774be85ccc946a8d7d79fe0dcdd52ece900755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20St=C3=B6ggl?= Date: Tue, 11 Jul 2017 14:25:23 +0200 Subject: [PATCH 092/438] Fix cnn outside test - http://www.cnn.com redirects users from countries outside of the US to the "http://edition.cnn.com/" drop location - Use http://edition.cnn.com, which does not redirect - even in the US - Fix https://github.com/Microsoft/cpprestsdk/issues/27 --- Release/tests/functional/http/client/outside_tests.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Release/tests/functional/http/client/outside_tests.cpp b/Release/tests/functional/http/client/outside_tests.cpp index b1da9c23e7..463b04bafd 100644 --- a/Release/tests/functional/http/client/outside_tests.cpp +++ b/Release/tests/functional/http/client/outside_tests.cpp @@ -39,7 +39,8 @@ TEST_FIXTURE(uri_address, outside_cnn_dot_com) { handle_timeout([] { - http_client client(U("http://www.cnn.com/")); + // http://www.cnn.com redirects users from countries outside of the US to the "http://edition.cnn.com/" drop location + http_client client(U("http://edition.cnn.com/")); // CNN's main page doesn't use chunked transfer encoding. http_response response = client.request(methods::GET).get(); From 5d138eb24f0fe2240639b739662d7d2ab850cd7f Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Tue, 11 Jul 2017 17:30:24 +0200 Subject: [PATCH 093/438] cleanup the changes --- .../src/http/client/http_client_winhttp.cpp | 119 +----------------- 1 file changed, 1 insertion(+), 118 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index ce649f9013..75a9f9767a 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -88,58 +88,6 @@ static utility::string_t parse_reason_phrase(HINTERNET request_handle) trim_nulls(phrase); return phrase; } -/* -#ifndef CPPREST_TARGET_XP -// Helper function to get a DWORD from Registry. -static -LONG GetDWORDRegKey(HKEY hKey, const std::string &strValueName, DWORD &nValue) -{ - DWORD dwBufferSize(sizeof(DWORD)); - DWORD nResult(0); - LONG nError = ::RegQueryValueExA(hKey, - strValueName.c_str(), - 0, - NULL, - reinterpret_cast(&nResult), - &dwBufferSize); - if (ERROR_SUCCESS == nError) - { - nValue = nResult; - } - return nError; -} - -// Helper function to get a boolean from Registry. -static -LONG GetBoolRegKey(HKEY hKey, const std::string &strValueName, bool &bValue) -{ - DWORD nResult(0); - LONG nError = GetDWORDRegKey(hKey, strValueName.c_str(), nResult); - if (ERROR_SUCCESS == nError) - { - bValue = (nResult != 0) ? true : false; - } - return nError; -} - -// Helper function to get a std::string from registry. -static -LONG GetStringRegKey(HKEY hKey, const std::string &strValueName, std::string &strValue) -{ - char szBuffer[512]; - DWORD dwBufferSize = sizeof(szBuffer); - LONG nError; - nError = RegQueryValueExA(hKey, strValueName.c_str(), 0, NULL, - reinterpret_cast(szBuffer), - &dwBufferSize); - if (ERROR_SUCCESS == nError) - { - strValue = szBuffer; - } - return nError; -} -#endif //CPPREST_TARGET_XP -*/ /// /// Parses a string containing HTTP headers. @@ -419,19 +367,15 @@ class winhttp_client : public _http_client_communicator utility::string_t proxy_str; http::uri uri; - std::ofstream ifs("hate_windows.txt", std::ios::out); - const auto& config = client_config(); if(config.proxy().is_disabled()) { - ifs << "config.proxy().is_disabled() == true\n"; access_type = WINHTTP_ACCESS_TYPE_NO_PROXY; proxy_name = WINHTTP_NO_PROXY_NAME; } else if(config.proxy().is_default() || config.proxy().is_auto_discovery()) { - ifs << "config.proxy().is_default() || config.proxy().is_auto_discovery() == true\n"; access_type = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; proxy_name = WINHTTP_NO_PROXY_NAME; #ifndef CPPREST_TARGET_XP @@ -441,70 +385,9 @@ class winhttp_client : public _http_client_communicator } else { - /* - auto getProxyFromRegistry = [](std::string &proxyURL) { - HKEY hKey; - LONG lRes = RegOpenKeyExA(HKEY_CURRENT_USER, - "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", - 0, - KEY_READ, - &hKey); - if (lRes != ERROR_SUCCESS) - { - return lRes; - } - - bool isEnabled = false; - lRes = GetBoolRegKey(hKey, "ProxyEnable", isEnabled); - - if (lRes != ERROR_SUCCESS) - { - return lRes; - } - if (!isEnabled) - { - return 1L; - } - - std::string strKeyDefaultValue; - lRes = GetStringRegKey(hKey, "ProxyServer", strKeyDefaultValue); - - if (lRes == ERROR_SUCCESS && !strKeyDefaultValue.empty()) - { - proxyURL = strKeyDefaultValue; - return ERROR_SUCCESS; - } - - return lRes; - }; - - std::string proxyAdress; - if (getProxyFromRegistry(proxyAdress) == ERROR_SUCCESS) - { - access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; - proxy_str = utility::conversions::to_string_t(proxyAdress).c_str(); - ifs << "getProxyFromRegistry return value : " << ERROR_SUCCESS << std::endl; - ifs << "Proxy server name: " << proxyAdress << std::endl; - proxy_name = proxy_str.c_str(); - } - else - { - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyInfo; - BOOL result = WinHttpGetIEProxyConfigForCurrentUser(&proxyInfo); - ifs << "WinHttpGetIEProxyConfigForCurrentUser return value : " << result << std::endl; - ifs << "Proxy server list: " << proxyInfo.lpszProxy << std::endl; - if (proxyInfo.lpszProxy != nullptr && result) - { - access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; - proxy_str = proxyInfo.lpszProxy; - proxy_name = proxy_str.c_str(); - } - }*/ WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyInfo; BOOL result = WinHttpGetIEProxyConfigForCurrentUser(&proxyInfo); - ifs << "WinHttpGetIEProxyConfigForCurrentUser return value : " << result << std::endl; - ifs << "Proxy server list: " << proxyInfo.lpszProxy << std::endl; - if (proxyInfo.lpszProxy != nullptr && result) + if (result && proxyInfo.lpszProxy != nullptr) { access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; proxy_str = proxyInfo.lpszProxy; From 11fd953e8caccf5e86e435081400d2d527ee4b55 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Wed, 12 Jul 2017 09:14:27 +0200 Subject: [PATCH 094/438] intedation --- .../src/http/client/http_client_winhttp.cpp | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 75a9f9767a..025095564d 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -377,23 +377,23 @@ class winhttp_client : public _http_client_communicator else if(config.proxy().is_default() || config.proxy().is_auto_discovery()) { access_type = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; - proxy_name = WINHTTP_NO_PROXY_NAME; + proxy_name = WINHTTP_NO_PROXY_NAME; #ifndef CPPREST_TARGET_XP - if(IsWindows8Point1OrGreater()) - { - access_type = WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY; - } - else - { - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyInfo; - BOOL result = WinHttpGetIEProxyConfigForCurrentUser(&proxyInfo); - if (result && proxyInfo.lpszProxy != nullptr) - { - access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; - proxy_str = proxyInfo.lpszProxy; - proxy_name = proxy_str.c_str(); - } - } + if(IsWindows8Point1OrGreater()) + { + access_type = WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY; + } + else + { + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyInfo; + BOOL result = WinHttpGetIEProxyConfigForCurrentUser(&proxyInfo); + if (result && proxyInfo.lpszProxy != nullptr) + { + access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; + proxy_str = proxyInfo.lpszProxy; + proxy_name = proxy_str.c_str(); + } + } #endif } else From 14060016a96be47508960323c61a581a773e442d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20St=C3=B6ggl?= Date: Wed, 12 Jul 2017 14:50:08 +0200 Subject: [PATCH 095/438] Fix google outside tests - http://www.google.com redirects country specifically - Use http://code.google.com, which does not redirect (so far) --- .../tests/functional/http/client/outside_tests.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Release/tests/functional/http/client/outside_tests.cpp b/Release/tests/functional/http/client/outside_tests.cpp index 463b04bafd..4ac5a23632 100644 --- a/Release/tests/functional/http/client/outside_tests.cpp +++ b/Release/tests/functional/http/client/outside_tests.cpp @@ -84,7 +84,8 @@ TEST_FIXTURE(uri_address, outside_wikipedia_compressed_http_response) TEST_FIXTURE(uri_address, outside_google_dot_com) { - http_client client(U("http://www.google.com/")); + // Use code.google.com instead of www.google.com, which redirects + http_client client(U("http://code.google.com/")); http_request request(methods::GET); for (int i = 0; i < 2; ++i) { @@ -97,7 +98,8 @@ TEST_FIXTURE(uri_address, multiple_https_requests) { handle_timeout([&] { - http_client client(U("https://www.google.com/")); + // Use code.google.com instead of www.google.com, which redirects + http_client client(U("https://code.google.com/")); http_response response; for(int i = 0; i < 5; ++i) @@ -113,7 +115,8 @@ TEST_FIXTURE(uri_address, reading_google_stream) { handle_timeout([&] { - http_client simpleclient(U("http://www.google.com/")); + // Use code.google.com instead of www.google.com, which redirects + http_client simpleclient(U("http://code.google.com/")); utility::string_t path = m_uri.query(); http_response response = simpleclient.request(::http::methods::GET).get(); @@ -123,7 +126,9 @@ TEST_FIXTURE(uri_address, reading_google_stream) streams::rawptr_buffer temp(chars, sizeof(chars)); VERIFY_ARE_EQUAL(response.body().read(temp, 70).get(), 70); - VERIFY_ARE_EQUAL(strcmp((const char *) chars, "\n \n Date: Thu, 13 Jul 2017 10:00:12 +0200 Subject: [PATCH 096/438] Fix build error with glibc 2.26, xlocale.h - Do not include xlocale.h on systems, where __GLIBC__ is defined xlocale.h has been removed from glibc 2.26 The include of locale.h in asyncrt_utils.h is sufficient Further details: https://sourceware.org/git/?p=glibc.git;a=commit;h=f0be25b - Fixes https://github.com/Microsoft/cpprestsdk/issues/485 --- Release/include/cpprest/asyncrt_utils.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index 169ec3a203..fac70a91a9 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -29,7 +29,10 @@ #ifndef _WIN32 #include -#if !defined(ANDROID) && !defined(__ANDROID__) // CodePlex 269 +#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(__GLIBC__) // CodePlex 269 +/* Systems using glibc: xlocale.h has been removed from glibc 2.26 + The above include of locale.h is sufficient + Further details: https://sourceware.org/git/?p=glibc.git;a=commit;h=f0be25b6336db7492e47d2e8e72eb8af53b5506d */ #include #endif #endif From f0238faeeb60843fe8dcf0a376fe0fda49d8d653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Meusel?= Date: Fri, 14 Jul 2017 13:30:47 +0200 Subject: [PATCH 097/438] FIX: make uri_builder::to_string(), ::to_uri() const --- Release/include/cpprest/uri_builder.h | 4 ++-- Release/src/uri/uri_builder.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Release/include/cpprest/uri_builder.h b/Release/include/cpprest/uri_builder.h index 8464d1e0af..4827534249 100644 --- a/Release/include/cpprest/uri_builder.h +++ b/Release/include/cpprest/uri_builder.h @@ -261,13 +261,13 @@ namespace web /// Combine and validate the URI components into a encoded string. An exception will be thrown if the URI is invalid. /// /// The created URI as a string. - _ASYNCRTIMP utility::string_t to_string(); + _ASYNCRTIMP utility::string_t to_string() const; /// /// Combine and validate the URI components into a URI class instance. An exception will be thrown if the URI is invalid. /// /// The create URI as a URI class instance. - _ASYNCRTIMP uri to_uri(); + _ASYNCRTIMP uri to_uri() const; /// /// Validate the generated URI from all existing components of this uri_builder. diff --git a/Release/src/uri/uri_builder.cpp b/Release/src/uri/uri_builder.cpp index 46f599bbcc..b7d08b6380 100644 --- a/Release/src/uri/uri_builder.cpp +++ b/Release/src/uri/uri_builder.cpp @@ -91,12 +91,12 @@ uri_builder &uri_builder::append(const http::uri &relative_uri) return *this; } -utility::string_t uri_builder::to_string() +utility::string_t uri_builder::to_string() const { return to_uri().to_string(); } -uri uri_builder::to_uri() +uri uri_builder::to_uri() const { return uri(m_uri); } From 2dcf4fd187d2ca6ce32a9b1ad9b01bcdb8fb08d5 Mon Sep 17 00:00:00 2001 From: Owen Rudge Date: Mon, 17 Jul 2017 12:03:05 +0100 Subject: [PATCH 098/438] Add support for retrieving remote address in HTTP listener --- Release/include/cpprest/http_msg.h | 12 ++++++++++++ Release/src/http/listener/http_server_asio.cpp | 3 +++ .../src/http/listener/http_server_httpsys.cpp | 16 ++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/Release/include/cpprest/http_msg.h b/Release/include/cpprest/http_msg.h index 72a07fdd62..8ca25edc69 100644 --- a/Release/include/cpprest/http_msg.h +++ b/Release/include/cpprest/http_msg.h @@ -715,6 +715,8 @@ class _http_request final : public http::details::http_msg_base, public std::ena _ASYNCRTIMP void set_request_uri(const uri&); + const utility::string_t& remote_address() const { return m_remote_address; } + const pplx::cancellation_token &cancellation_token() const { return m_cancellationToken; } void set_cancellation_token(const pplx::cancellation_token &token) @@ -755,6 +757,8 @@ class _http_request final : public http::details::http_msg_base, public std::ena void _set_base_uri(const http::uri &base_uri) { m_base_uri = base_uri; } + void _set_remote_address(const utility::string_t &remote_address) { m_remote_address = remote_address; } + private: // Actual initiates sending the response, without checking if a response has already been sent. @@ -778,6 +782,8 @@ class _http_request final : public http::details::http_msg_base, public std::ena std::shared_ptr m_progress_handler; pplx::task_completion_event m_response; + + utility::string_t m_remote_address; }; @@ -869,6 +875,12 @@ class http_request /// const http_headers &headers() const { return _m_impl->headers(); } + /// + /// Returns a string representation of the remote IP address. + /// + /// The remote IP address. + const utility::string_t& get_remote_address() const { return _m_impl->remote_address(); } + /// /// Extract the body of the request message as a string value, checking that the content type is a MIME text type. /// A body can only be extracted once because in some cases an optimization is made where the data is 'moved' out. diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 8b155c23f2..99351c13a0 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -654,6 +654,9 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys m_close = true; } + // Get the remote IP address + m_request._get_impl()->_set_remote_address(utility::conversions::to_string_t(m_socket->remote_endpoint().address().to_string())); + return handle_headers(); } } diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp index ce1717ea3d..2604bfc8e8 100644 --- a/Release/src/http/listener/http_server_httpsys.cpp +++ b/Release/src/http/listener/http_server_httpsys.cpp @@ -555,6 +555,22 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD m_msg.set_method(parse_request_method(m_request)); parse_http_headers(m_request->Headers, m_msg.headers()); + // Retrieve the remote IP address + std::vector remoteAddressBuffer(50); + PVOID inAddr; + + if (m_request->Address.pRemoteAddress->sa_family == AF_INET6) + { + inAddr = &reinterpret_cast(m_request->Address.pRemoteAddress)->sin6_addr; + } + else + { + inAddr = &reinterpret_cast(m_request->Address.pRemoteAddress)->sin_addr; + } + + InetNtopW(m_request->Address.pRemoteAddress->sa_family, inAddr, &remoteAddressBuffer[0], remoteAddressBuffer.size()); + m_msg._get_impl()->_set_remote_address(std::wstring(&remoteAddressBuffer[0])); + // Start reading in body from the network. m_msg._get_impl()->_prepare_to_receive_data(); read_request_body_chunk(); From 48244346d3ef270976dab2a61c56631072da4eb1 Mon Sep 17 00:00:00 2001 From: Owen Rudge Date: Mon, 17 Jul 2017 14:19:25 +0100 Subject: [PATCH 099/438] Add test for request.remote_address() --- .../http/listener/request_handler_tests.cpp | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Release/tests/functional/http/listener/request_handler_tests.cpp b/Release/tests/functional/http/listener/request_handler_tests.cpp index 8c9a525a74..33f7d0ea85 100644 --- a/Release/tests/functional/http/listener/request_handler_tests.cpp +++ b/Release/tests/functional/http/listener/request_handler_tests.cpp @@ -448,6 +448,41 @@ TEST_FIXTURE(uri_address, test_leaks) listener.close().wait(); } +TEST_FIXTURE(uri_address, remote_address) +{ + http_listener listener(U("http://localhost:45678/path1")); + listener.open().wait(); + + test_http_client::scoped_client client(U("http://localhost:45678/")); + test_http_client * p_client = client.client(); + + volatile unsigned long requestCount = 0; + + listener.support(methods::GET, [&requestCount](http_request request) + { + const string_t& remoteAddr = request.get_remote_address(); + const string_t& localhost4 = string_t(U("127.0.0.1")); + const string_t& localhost6 = string_t(U("::1")); + + // We can't guarantee that the host has both IPv4 and IPv6 available, so check for either IP + VERIFY_IS_TRUE((remoteAddr == localhost4) || (remoteAddr == localhost6)); + + os_utilities::interlocked_increment(&requestCount); + request.reply(status_codes::NoContent); + }); + + // Send a request to the listener + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1"))); + + p_client->next_response().then([](test_response *p_response) + { + http_asserts::assert_test_response_equals(p_response, status_codes::NoContent); + }).wait(); + + VERIFY_IS_TRUE(requestCount >= 1); + listener.close().wait(); +} + } }}}} From 55ea6924aac5a5a39fc484c12030cb679066b181 Mon Sep 17 00:00:00 2001 From: deeringc Date: Mon, 17 Jul 2017 15:01:47 +0100 Subject: [PATCH 100/438] Adding 308 "Permanent Redirect" to http_constants.dat As per https://tools.ietf.org/html/rfc7538#section-3 --- Release/include/cpprest/details/http_constants.dat | 1 + 1 file changed, 1 insertion(+) diff --git a/Release/include/cpprest/details/http_constants.dat b/Release/include/cpprest/details/http_constants.dat index c408556b19..c867b4d07a 100644 --- a/Release/include/cpprest/details/http_constants.dat +++ b/Release/include/cpprest/details/http_constants.dat @@ -28,6 +28,7 @@ DAT(SeeOther, 303, _XPLATSTR("See Other")) DAT(NotModified, 304, _XPLATSTR("Not Modified")) DAT(UseProxy, 305, _XPLATSTR("Use Proxy")) DAT(TemporaryRedirect, 307, _XPLATSTR("Temporary Redirect")) +DAT(PermanentRedirect, 308, _XPLATSTR("Permanent Redirect")) DAT(BadRequest, 400, _XPLATSTR("Bad Request")) DAT(Unauthorized, 401, _XPLATSTR("Unauthorized")) DAT(PaymentRequired, 402, _XPLATSTR("Payment Required")) From 70c1b14f39f5d47984fdd8a31fc357ebb5a37851 Mon Sep 17 00:00:00 2001 From: Force Charlie Date: Thu, 20 Jul 2017 14:39:21 +0800 Subject: [PATCH 101/438] fix lambda capture 'this' is not used, clang 5.0 on ubuntu 16.04 --- Release/src/uri/uri.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Release/src/uri/uri.cpp b/Release/src/uri/uri.cpp index fb395edf5d..3157b96a6d 100644 --- a/Release/src/uri/uri.cpp +++ b/Release/src/uri/uri.cpp @@ -22,12 +22,12 @@ utility::string_t uri_components::join() // canonicalize components first // convert scheme to lowercase - std::transform(m_scheme.begin(), m_scheme.end(), m_scheme.begin(), [this](utility::char_t c) { + std::transform(m_scheme.begin(), m_scheme.end(), m_scheme.begin(), [](utility::char_t c) { return (utility::char_t)tolower(c); }); // convert host to lowercase - std::transform(m_host.begin(), m_host.end(), m_host.begin(), [this](utility::char_t c) { + std::transform(m_host.begin(), m_host.end(), m_host.begin(), [](utility::char_t c) { return (utility::char_t)tolower(c); }); From dd8eddd46f46678dee8b1bf476914da41b17173a Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 24 Jul 2017 08:50:31 -0700 Subject: [PATCH 102/438] Disable setting secure protocols on XP. Fixes #510. --- Release/src/http/client/http_client_winhttp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 3eee959aff..52bf771a16 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -449,6 +449,7 @@ class winhttp_client : public _http_client_communicator } #endif //Enable TLS 1.1 and 1.2 +#if !defined(CPPREST_TARGET_XP) BOOL win32_result(FALSE); DWORD secure_protocols(WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2); @@ -457,6 +458,7 @@ class winhttp_client : public _http_client_communicator { return report_failure(_XPLATSTR("Error setting session options")); } +#endif config._invoke_nativesessionhandle_options(m_hSession); From b2efa45ef3d50eedb965fea4d466b6bce96e01e7 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Wed, 2 Aug 2017 10:08:56 +0200 Subject: [PATCH 103/438] enable crl checks for windows tls --- Release/src/http/client/http_client_winhttp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 52bf771a16..7fc5c3d15e 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -437,7 +437,7 @@ class winhttp_client : public _http_client_communicator } } -#if 0 // Work in progress. Enable this to support server certificate revocation check +#if 1 // Work in progress. Enable this to support server certificate revocation check if( m_secure ) { DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; From 3f47656ab14f6091dc85b20b18e7a434f5014ea9 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Wed, 2 Aug 2017 11:43:37 +0200 Subject: [PATCH 104/438] use the right handle --- Release/src/http/client/http_client_winhttp.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 7fc5c3d15e..578b644366 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -437,7 +437,7 @@ class winhttp_client : public _http_client_communicator } } -#if 1 // Work in progress. Enable this to support server certificate revocation check +#if 0 // Work in progress. Enable this to support server certificate revocation check if( m_secure ) { DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; @@ -542,6 +542,17 @@ class winhttp_client : public _http_client_communicator return; } + if (m_secure) + { + DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; + if (!WinHttpSetOption(winhttp_context->m_request_handle, WINHTTP_OPTION_ENABLE_FEATURE, &dwEnableSSLRevocOpt, sizeof(dwEnableSSLRevocOpt))) + { + auto errorCode = GetLastError(); + request->report_error(errorCode, build_error_msg(errorCode, "Error enabling SSL revocation check")); + return; + } + } + if(proxy_info_required) { auto result = WinHttpSetOption( From ba1fdef46c30e27866ec4d42c997acd7eebff9dc Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Thu, 3 Aug 2017 13:54:38 +0200 Subject: [PATCH 105/438] delete unused code --- Release/src/http/client/http_client_winhttp.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 578b644366..b65f92e734 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -437,17 +437,6 @@ class winhttp_client : public _http_client_communicator } } -#if 0 // Work in progress. Enable this to support server certificate revocation check - if( m_secure ) - { - DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; - if(!WinHttpSetOption(m_hSession, WINHTTP_OPTION_ENABLE_FEATURE, &dwEnableSSLRevocOpt, sizeof(dwEnableSSLRevocOpt))) - { - DWORD dwError = GetLastError(); dwError; - return report_failure(U("Error enabling SSL revocation check")); - } - } -#endif //Enable TLS 1.1 and 1.2 #if !defined(CPPREST_TARGET_XP) BOOL win32_result(FALSE); @@ -542,6 +531,7 @@ class winhttp_client : public _http_client_communicator return; } + // Enable the certificate revocation check if (m_secure) { DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; From 9bcde8b4ab75aab490ce6e16ffae5f44c7d68eed Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Fri, 11 Aug 2017 16:06:36 +0200 Subject: [PATCH 106/438] c'tor early return if the string is empty --- Release/src/utilities/web_utilities.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Release/src/utilities/web_utilities.cpp b/Release/src/utilities/web_utilities.cpp index 367c95c2f4..5a852c0e5d 100644 --- a/Release/src/utilities/web_utilities.cpp +++ b/Release/src/utilities/web_utilities.cpp @@ -92,6 +92,11 @@ plaintext_string winrt_encryption::decrypt() const win32_encryption::win32_encryption(const std::wstring &data) : m_numCharacters(data.size()) { + if (m_numCharacters == 0) + { + return; + } + const auto dataNumBytes = data.size() * sizeof(std::wstring::value_type); m_buffer.resize(dataNumBytes); memcpy_s(m_buffer.data(), m_buffer.size(), data.c_str(), dataNumBytes); From e212141f44cd2d3ada5b9b28d08625e817adc509 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Mon, 14 Aug 2017 09:49:02 +0200 Subject: [PATCH 107/438] use a early return in case of empty string --- Release/src/utilities/web_utilities.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Release/src/utilities/web_utilities.cpp b/Release/src/utilities/web_utilities.cpp index 5a852c0e5d..f17b5ab099 100644 --- a/Release/src/utilities/web_utilities.cpp +++ b/Release/src/utilities/web_utilities.cpp @@ -92,6 +92,7 @@ plaintext_string winrt_encryption::decrypt() const win32_encryption::win32_encryption(const std::wstring &data) : m_numCharacters(data.size()) { + // Early return because CryptProtectMemory crashs with empty string if (m_numCharacters == 0) { return; From d947fb5cd543ab330595ad03729363eeb5387434 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Tue, 15 Aug 2017 17:02:34 +0200 Subject: [PATCH 108/438] add test for the crash bug --- Release/tests/functional/utils/CMakeLists.txt | 1 + Release/tests/functional/utils/stdafx.h | 3 +- .../utils/win32_encryption_tests.cpp | 44 +++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 Release/tests/functional/utils/win32_encryption_tests.cpp diff --git a/Release/tests/functional/utils/CMakeLists.txt b/Release/tests/functional/utils/CMakeLists.txt index e2d0e6bca3..5c6577b24e 100644 --- a/Release/tests/functional/utils/CMakeLists.txt +++ b/Release/tests/functional/utils/CMakeLists.txt @@ -4,6 +4,7 @@ set(SOURCES strings.cpp macro_test.cpp nonce_generator_tests.cpp + win32_encryption_tests.cpp stdafx.cpp ) diff --git a/Release/tests/functional/utils/stdafx.h b/Release/tests/functional/utils/stdafx.h index 32455df0e1..8188bec2e5 100644 --- a/Release/tests/functional/utils/stdafx.h +++ b/Release/tests/functional/utils/stdafx.h @@ -16,6 +16,7 @@ #include "cpprest/uri.h" #include "cpprest/asyncrt_utils.h" +#include "cpprest/details/web_utilities.h" #include "unittestpp.h" -#include "utils_tests.h" \ No newline at end of file +#include "utils_tests.h" diff --git a/Release/tests/functional/utils/win32_encryption_tests.cpp b/Release/tests/functional/utils/win32_encryption_tests.cpp new file mode 100644 index 0000000000..2ec4b21a68 --- /dev/null +++ b/Release/tests/functional/utils/win32_encryption_tests.cpp @@ -0,0 +1,44 @@ +/*** +* Copyright (C) Microsoft. All rights reserved. +* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +* +* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +* +* win32_encryption_tests.cpp +* +* Tests for win32_encryption class. +* +* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +****/ + +#include "stdafx.h" + +using namespace utility; + +namespace tests { namespace functional { namespace utils_tests { + +#if defined(_WIN32) && !defined(CPPREST_TARGET_XP) && !defined(__cplusplus_winrt) +SUITE(win32_encryption) +{ + +TEST(win32_encryption_random_string) +{ + utility::string_t rndStr = utility::conversions::to_string_t("random string"); + web::details::win32_encryption enc(rndStr); + + VERIFY_ARE_EQUAL(*enc.decrypt(), rndStr); +} + +TEST(win32_encryption_empty_string) +{ + utility::string_t emptyStr = utility::conversions::to_string_t(""); + web::details::win32_encryption enc(emptyStr); + + VERIFY_ARE_EQUAL(*enc.decrypt(), emptyStr); +} + +} // SUITE(win32_encryption) + +#endif + +}}} From 06422756b0bffbd5e05aff8f9a6d6c9bdc2c7318 Mon Sep 17 00:00:00 2001 From: Elvis Dukaj Date: Tue, 22 Aug 2017 12:55:25 +0200 Subject: [PATCH 109/438] patch in SSL_R_SHORT_READ from https://github.com/LocutusOfBorg/websocketpp/commit/a1103320ae8d3b4fa0ec5ee80a95a12e2bc0ca20 --- .../websocketpp/websocketpp/transport/asio/security/tls.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp b/Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp index 8434a5c3d9..8932655803 100644 --- a/Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp +++ b/Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp @@ -307,8 +307,13 @@ class connection : public lib::enable_shared_from_this { */ lib::error_code translate_ec(boost::system::error_code ec) { if (ec.category() == boost::asio::error::get_ssl_category()) { +#if defined SSL_R_SHORT_READ if (ERR_GET_REASON(ec.value()) == SSL_R_SHORT_READ) { return make_error_code(transport::error::tls_short_read); +#else + if (ERR_GET_REASON(ec.value()) == boost::asio::ssl::error::stream_truncated) { + return make_error_code(boost::asio::ssl::error::stream_truncated); +#endif } else { // We know it is a TLS related error, but otherwise don't know // more. Pass through as TLS generic. From 91a548eb7373ffd67feb4f10919efdf707076fe8 Mon Sep 17 00:00:00 2001 From: Christoph Albert Date: Wed, 23 Aug 2017 16:00:34 +0200 Subject: [PATCH 110/438] Fixed proxy credentials for http_client_asio --- Release/src/http/client/http_client_asio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 2183c9c389..19e09b2427 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -809,7 +809,7 @@ class asio_context : public request_context, public std::enable_shared_from_this { std::string header; header.append("Proxy-Authorization: Basic "); - header.append(generate_base64_userpass(m_http_client->client_config().credentials())); + header.append(generate_base64_userpass(m_http_client->client_config().proxy().credentials())); header.append(CRLF); return header; } From da058b3dd6670cbf113ab2b9f5a449f6956f0fa9 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 26 Aug 2017 01:14:18 -0700 Subject: [PATCH 111/438] Don't assume AF_INET6 or AF_INET --- Release/src/http/listener/http_server_httpsys.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp index 2604bfc8e8..d4872d17db 100644 --- a/Release/src/http/listener/http_server_httpsys.cpp +++ b/Release/src/http/listener/http_server_httpsys.cpp @@ -557,19 +557,23 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD // Retrieve the remote IP address std::vector remoteAddressBuffer(50); - PVOID inAddr; if (m_request->Address.pRemoteAddress->sa_family == AF_INET6) { - inAddr = &reinterpret_cast(m_request->Address.pRemoteAddress)->sin6_addr; + auto inAddr = &reinterpret_cast(m_request->Address.pRemoteAddress)->sin6_addr; + InetNtopW(AF_INET6, inAddr, &remoteAddressBuffer[0], remoteAddressBuffer.size()); + } + else if (m_request->Address.pRemoteAddress->sa_family == AF_INET) + { + auto inAddr = &reinterpret_cast(m_request->Address.pRemoteAddress)->sin_addr; + InetNtopW(AF_INET, inAddr, &remoteAddressBuffer[0], remoteAddressBuffer.size()); } else { - inAddr = &reinterpret_cast(m_request->Address.pRemoteAddress)->sin_addr; + remoteAddressBuffer[0] = L'\0'; } - InetNtopW(m_request->Address.pRemoteAddress->sa_family, inAddr, &remoteAddressBuffer[0], remoteAddressBuffer.size()); - m_msg._get_impl()->_set_remote_address(std::wstring(&remoteAddressBuffer[0])); + m_msg._get_impl()->_set_remote_address(&remoteAddressBuffer[0]); // Start reading in body from the network. m_msg._get_impl()->_prepare_to_receive_data(); From 64dd0676ba85f3312fc3b4975f85e149419310bc Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 26 Aug 2017 01:41:10 -0700 Subject: [PATCH 112/438] Add comment(lib) for Ws2_32 --- Release/src/http/listener/http_server_httpsys.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp index d4872d17db..9b58d20ef1 100644 --- a/Release/src/http/listener/http_server_httpsys.cpp +++ b/Release/src/http/listener/http_server_httpsys.cpp @@ -17,6 +17,8 @@ #if _WIN32_WINNT >= _WIN32_WINNT_VISTA +#pragma comment(lib, "Ws2_32") + #include "http_server_httpsys.h" #include "http_server_impl.h" From 90ab8f7a2e27863bbdb0585478587ad05504f9da Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 26 Aug 2017 01:49:03 -0700 Subject: [PATCH 113/438] Reformat --- .../src/http/client/http_client_winhttp.cpp | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index b65f92e734..d0bea3284e 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -531,17 +531,17 @@ class winhttp_client : public _http_client_communicator return; } - // Enable the certificate revocation check - if (m_secure) - { - DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; - if (!WinHttpSetOption(winhttp_context->m_request_handle, WINHTTP_OPTION_ENABLE_FEATURE, &dwEnableSSLRevocOpt, sizeof(dwEnableSSLRevocOpt))) - { - auto errorCode = GetLastError(); - request->report_error(errorCode, build_error_msg(errorCode, "Error enabling SSL revocation check")); - return; - } - } + // Enable the certificate revocation check + if (m_secure) + { + DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; + if (!WinHttpSetOption(winhttp_context->m_request_handle, WINHTTP_OPTION_ENABLE_FEATURE, &dwEnableSSLRevocOpt, sizeof(dwEnableSSLRevocOpt))) + { + auto errorCode = GetLastError(); + request->report_error(errorCode, build_error_msg(errorCode, "Error enabling SSL revocation check")); + return; + } + } if(proxy_info_required) { From 92f1821b40e42bb0bc0cc5cef16fac1bc4812cc1 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 26 Aug 2017 01:54:16 -0700 Subject: [PATCH 114/438] Clean up memory after call to WinHttpGetIEProxyConfigForCurrentUser --- .../src/http/client/http_client_winhttp.cpp | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 025095564d..c9897f2717 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -385,7 +385,25 @@ class winhttp_client : public _http_client_communicator } else { - WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyInfo; + struct raii_ie_proxy_config : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG + { + raii_ie_proxy_config() + { + memset(this, 0, sizeof(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG)); + } + + ~raii_ie_proxy_config() + { + if (lpszProxy) + ::GlobalFree(lpszProxy); + if (lpszProxyBypass) + ::GlobalFree(lpszProxyBypass); + if (lpszAutoConfigUrl) + ::GlobalFree(lpszAutoConfigUrl); + } + }; + + raii_ie_proxy_config proxyInfo; BOOL result = WinHttpGetIEProxyConfigForCurrentUser(&proxyInfo); if (result && proxyInfo.lpszProxy != nullptr) { From 065d0752b20492ba384b533e95a5ee5ac03f0eea Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 26 Aug 2017 02:45:08 -0700 Subject: [PATCH 115/438] Simplify PR #494 --- Release/samples/BingRequest/bingrequest.cpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/Release/samples/BingRequest/bingrequest.cpp b/Release/samples/BingRequest/bingrequest.cpp index 066d210dd2..726d6d194a 100644 --- a/Release/samples/BingRequest/bingrequest.cpp +++ b/Release/samples/BingRequest/bingrequest.cpp @@ -26,27 +26,22 @@ web::http::client::http_client_config client_config_for_proxy() { web::http::client::http_client_config client_config; #ifdef _WIN32 - wchar_t* pValue; - size_t len; + wchar_t* pValue = nullptr; + std::unique_ptr holder(nullptr, [](wchar_t* p) { free(p); }); + size_t len = 0; auto err = _wdupenv_s(&pValue, &len, L"http_proxy"); + if (pValue) + holder.reset(pValue); if (!err && pValue && len) { - std::unique_ptr holder(pValue, [](wchar_t* p) { free(p); }); std::wstring env_http_proxy_string(pValue, len - 1); #else if(const char* env_http_proxy = std::getenv("http_proxy")) { std::string env_http_proxy_string(env_http_proxy); #endif - web::web_proxy proxy; - if (env_http_proxy_string != U("auto")) - { - uri proxy_uri(env_http_proxy_string); - proxy = std::move(web::web_proxy(proxy_uri)); - } + if (env_http_proxy_string == U("auto")) + client_config.set_proxy(web::web_proxy::use_auto_discovery); else - { - proxy = std::move(web::web_proxy(web::web_proxy::use_auto_discovery)); - } - client_config.set_proxy(proxy); + client_config.set_proxy(web::web_proxy(env_http_proxy_string)); } return client_config; From 9747bc3b13581fc4462aabf96f484ca877ad6fd4 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sun, 3 Sep 2017 01:41:03 -0700 Subject: [PATCH 116/438] Fix v141 warnings in websocketpp --- Release/libs/websocketpp/websocketpp/frame.hpp | 6 +++--- .../libs/websocketpp/websocketpp/impl/utilities_impl.hpp | 2 +- Release/libs/websocketpp/websocketpp/processors/hybi00.hpp | 2 +- Release/libs/websocketpp/websocketpp/processors/hybi13.hpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Release/libs/websocketpp/websocketpp/frame.hpp b/Release/libs/websocketpp/websocketpp/frame.hpp index 7179089bae..b6eb70a423 100644 --- a/Release/libs/websocketpp/websocketpp/frame.hpp +++ b/Release/libs/websocketpp/websocketpp/frame.hpp @@ -235,17 +235,17 @@ struct basic_header { /// The variable size component of a WebSocket frame header struct extended_header { extended_header() { - std::fill_n(this->bytes.begin(), MAX_EXTENDED_HEADER_LENGTH, 0x00); + std::fill_n(this->bytes.begin(), MAX_EXTENDED_HEADER_LENGTH, static_cast(0x00)); } extended_header(uint64_t payload_size) { - std::fill_n(this->bytes.begin(), MAX_EXTENDED_HEADER_LENGTH, 0x00); + std::fill_n(this->bytes.begin(), MAX_EXTENDED_HEADER_LENGTH, static_cast(0x00)); copy_payload(payload_size); } extended_header(uint64_t payload_size, uint32_t masking_key) { - std::fill_n(this->bytes.begin(), MAX_EXTENDED_HEADER_LENGTH, 0x00); + std::fill_n(this->bytes.begin(), MAX_EXTENDED_HEADER_LENGTH, static_cast(0x00)); // Copy payload size int offset = copy_payload(payload_size); diff --git a/Release/libs/websocketpp/websocketpp/impl/utilities_impl.hpp b/Release/libs/websocketpp/websocketpp/impl/utilities_impl.hpp index 6f86e22f58..0e7879d999 100644 --- a/Release/libs/websocketpp/websocketpp/impl/utilities_impl.hpp +++ b/Release/libs/websocketpp/websocketpp/impl/utilities_impl.hpp @@ -36,7 +36,7 @@ namespace utility { inline std::string to_lower(std::string const & in) { std::string out = in; - std::transform(out.begin(),out.end(),out.begin(),::tolower); + std::transform(out.begin(), out.end(), out.begin(), [](char ch) { return static_cast(::tolower(ch)); }); return out; } diff --git a/Release/libs/websocketpp/websocketpp/processors/hybi00.hpp b/Release/libs/websocketpp/websocketpp/processors/hybi00.hpp index d693a47442..4f7faf6481 100644 --- a/Release/libs/websocketpp/websocketpp/processors/hybi00.hpp +++ b/Release/libs/websocketpp/websocketpp/processors/hybi00.hpp @@ -421,7 +421,7 @@ class hybi00 : public processor { memcpy(result, reinterpret_cast(&num), 4); #endif } else { - std::fill(result,result+4,0); + std::fill(result,result+4, static_cast(0)); } } diff --git a/Release/libs/websocketpp/websocketpp/processors/hybi13.hpp b/Release/libs/websocketpp/websocketpp/processors/hybi13.hpp index 66e2e75f1a..ffff7bb21a 100644 --- a/Release/libs/websocketpp/websocketpp/processors/hybi13.hpp +++ b/Release/libs/websocketpp/websocketpp/processors/hybi13.hpp @@ -464,7 +464,7 @@ class hybi13 : public processor { std::fill( m_extended_header.bytes.begin(), m_extended_header.bytes.end(), - 0x00 + static_cast(0x00) ); } From fb92f6de9e35f638d60797c079865cef373e3f6b Mon Sep 17 00:00:00 2001 From: deeringc Date: Mon, 18 Sep 2017 11:39:54 +0100 Subject: [PATCH 117/438] Adding "429 - Too Many Requests" to the http constants --- Release/include/cpprest/details/http_constants.dat | 1 + 1 file changed, 1 insertion(+) diff --git a/Release/include/cpprest/details/http_constants.dat b/Release/include/cpprest/details/http_constants.dat index c867b4d07a..f2bd531be5 100644 --- a/Release/include/cpprest/details/http_constants.dat +++ b/Release/include/cpprest/details/http_constants.dat @@ -47,6 +47,7 @@ DAT(RequestUriTooLarge, 414, _XPLATSTR("Request Uri Too Large")) DAT(UnsupportedMediaType, 415, _XPLATSTR("Unsupported Media Type")) DAT(RangeNotSatisfiable, 416, _XPLATSTR("Requested range not satisfiable")) DAT(ExpectationFailed, 417, _XPLATSTR("Expectation Failed")) +DAT(TooManyRequests, 429, _XPLATSTR("Too Many Requests")) DAT(InternalError, 500, _XPLATSTR("Internal Error")) DAT(NotImplemented, 501, _XPLATSTR("Not Implemented")) DAT(BadGateway, 502, _XPLATSTR("Bad Gateway")) From d0658158acddf3c6d5ed8e59117eb222230d42e9 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 18 Sep 2017 18:13:33 -0700 Subject: [PATCH 118/438] Do not use imported targets for Boost because they're continually broken. --- Release/cmake/cpprest_find_boost.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Release/cmake/cpprest_find_boost.cmake b/Release/cmake/cpprest_find_boost.cmake index 1ff79121e3..6ac519bccc 100644 --- a/Release/cmake/cpprest_find_boost.cmake +++ b/Release/cmake/cpprest_find_boost.cmake @@ -24,7 +24,8 @@ function(cpprest_find_boost) endif() add_library(cpprestsdk_boost_internal INTERFACE) - if(NOT TARGET Boost::boost) + # FindBoost continually breaks imported targets whenever boost updates. + if(1) target_include_directories(cpprestsdk_boost_internal INTERFACE "$") target_link_libraries(cpprestsdk_boost_internal INTERFACE "$") else() From 23ac40a733cccbd34fa6a4afd65d25946852b452 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 18 Sep 2017 22:05:59 -0700 Subject: [PATCH 119/438] Do not use imported targets for Boost because they're continually broken. Part 2. --- Release/cmake/cpprest_find_boost.cmake | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Release/cmake/cpprest_find_boost.cmake b/Release/cmake/cpprest_find_boost.cmake index 6ac519bccc..9e8db2948a 100644 --- a/Release/cmake/cpprest_find_boost.cmake +++ b/Release/cmake/cpprest_find_boost.cmake @@ -27,7 +27,24 @@ function(cpprest_find_boost) # FindBoost continually breaks imported targets whenever boost updates. if(1) target_include_directories(cpprestsdk_boost_internal INTERFACE "$") - target_link_libraries(cpprestsdk_boost_internal INTERFACE "$") + set(_prev) + set(_libs) + foreach(_lib ${Boost_LIBRARIES}) + if(_lib STREQUAL "optimized" OR _lib STREQUAL "debug") + else() + if(_prev STREQUAL "optimized") + list(APPEND _libs "$<$>:${_lib}>") + elseif(_prev STREQUAL "debug") + list(APPEND _libs "$<$:${_lib}>") + else() + list(APPEND _libs "${_lib}") + endif() + endif() + set(_prev "${_lib}") + endforeach() + message(STATUS "_libs: ${_libs}") + target_link_libraries(cpprestsdk_boost_internal INTERFACE "$") + else() if(ANDROID) target_link_libraries(cpprestsdk_boost_internal INTERFACE From 180c72bfd8755af24466d53ccd7fc86f787819e3 Mon Sep 17 00:00:00 2001 From: deeringc Date: Sun, 1 Oct 2017 16:00:55 +0100 Subject: [PATCH 120/438] Add all remaining missing HTTP status codes I had been adding PRs for these as I encountered missing ones in my usage. I encountered another so I figured I would just go ahead and add all the remaining ones in one go. I left out 418 - "I'm a teapot", although I was tempted! ;) --- .../include/cpprest/details/http_constants.dat | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Release/include/cpprest/details/http_constants.dat b/Release/include/cpprest/details/http_constants.dat index f2bd531be5..f3d051f236 100644 --- a/Release/include/cpprest/details/http_constants.dat +++ b/Release/include/cpprest/details/http_constants.dat @@ -21,6 +21,9 @@ DAT(NonAuthInfo, 203, _XPLATSTR("Non-Authoritative Information")) DAT(NoContent, 204, _XPLATSTR("No Content")) DAT(ResetContent, 205, _XPLATSTR("Reset Content")) DAT(PartialContent, 206, _XPLATSTR("Partial Content")) +DAT(MultiStatus, 207, _XPLATSTR("Multi-Status")) +DAT(AlreadyReported, 208, _XPLATSTR("Already Reported")) +DAT(IMUsed, 226, _XPLATSTR("IM Used")) DAT(MultipleChoices, 300, _XPLATSTR("Multiple Choices")) DAT(MovedPermanently, 301, _XPLATSTR("Moved Permanently")) DAT(Found, 302, _XPLATSTR("Found")) @@ -47,13 +50,26 @@ DAT(RequestUriTooLarge, 414, _XPLATSTR("Request Uri Too Large")) DAT(UnsupportedMediaType, 415, _XPLATSTR("Unsupported Media Type")) DAT(RangeNotSatisfiable, 416, _XPLATSTR("Requested range not satisfiable")) DAT(ExpectationFailed, 417, _XPLATSTR("Expectation Failed")) +DAT(MisdirectedRequest, 421, _XPLATSTR("Misdirected Request")) +DAT(UnprocessableEntity, 422, _XPLATSTR(Unprocessable Entity")) +DAT(Locked, 423, _XPLATSTR(Locked")) +DAT(FailedDependency, 424, _XPLATSTR(Failed Dependency")) +DAT(UpgradeRequired, 426, _XPLATSTR(Upgrade Required")) +DAT(PreconditionRequired, 428, _XPLATSTR(Precondition Required")) DAT(TooManyRequests, 429, _XPLATSTR("Too Many Requests")) +DAT(RequestHeaderFieldsTooLarge, 431, _XPLATSTR("Request Header Fields Too Large")) +DAT(UnavailableForLegalReasons, 451, _XPLATSTR("Unavailable For Legal Reasons")) DAT(InternalError, 500, _XPLATSTR("Internal Error")) DAT(NotImplemented, 501, _XPLATSTR("Not Implemented")) DAT(BadGateway, 502, _XPLATSTR("Bad Gateway")) DAT(ServiceUnavailable, 503, _XPLATSTR("Service Unavailable")) DAT(GatewayTimeout, 504, _XPLATSTR("Gateway Time-out")) DAT(HttpVersionNotSupported, 505, _XPLATSTR("HTTP Version not supported")) +DAT(VariantAlsoNegotiates, 506, _XPLATSTR("Variant Also Negotiates")) +DAT(InsufficientStorage, 507, _XPLATSTR("Insufficient Storage")) +DAT(LoopDetected, 508, _XPLATSTR("Loop Detected")) +DAT(NotExtended, 510, _XPLATSTR("Not Extended")) +DAT(NetworkAuthenticationRequired, 511, _XPLATSTR("Network Authentication Required")) #endif // _PHRASES #ifdef _HEADER_NAMES From 0cffa77bad3c0b2122c0959910a0a861e09a93f8 Mon Sep 17 00:00:00 2001 From: Chris Deering Date: Sun, 1 Oct 2017 22:21:31 +0100 Subject: [PATCH 121/438] Adding has__field utility to json value Adding unit tests for has__field utilities --- Release/include/cpprest/json.h | 49 ++++++++++++++++ Release/src/json/json.cpp | 35 ++++++++++++ .../json/to_as_and_operators_tests.cpp | 57 ++++++++++++++++++- 3 files changed, 140 insertions(+), 1 deletion(-) diff --git a/Release/include/cpprest/json.h b/Release/include/cpprest/json.h index 5f2572ca01..f4987f5c21 100644 --- a/Release/include/cpprest/json.h +++ b/Release/include/cpprest/json.h @@ -544,6 +544,55 @@ namespace json /// True if the field exists, false otherwise. bool has_field(const utility::string_t &key) const; + /// + /// Tests for the presence of a number field + /// + /// The name of the field + /// True if the field exists, false otherwise. + _ASYNCRTIMP bool has_number_field(const utility::string_t &key) const; + + /// + /// Tests for the presence of an integer field + /// + /// The name of the field + /// True if the field exists, false otherwise. + _ASYNCRTIMP bool has_integer_field(const utility::string_t &key) const; + + /// + /// Tests for the presence of a double field + /// + /// The name of the field + /// True if the field exists, false otherwise. + _ASYNCRTIMP bool has_double_field(const utility::string_t &key) const; + + /// + /// Tests for the presence of a boolean field + /// + /// The name of the field + /// True if the field exists, false otherwise. + _ASYNCRTIMP bool has_boolean_field(const utility::string_t &key) const; + + /// + /// Tests for the presence of a string field + /// + /// The name of the field + /// True if the field exists, false otherwise. + _ASYNCRTIMP bool has_string_field(const utility::string_t &key) const; + + /// + /// Tests for the presence of an array field + /// + /// The name of the field + /// True if the field exists, false otherwise. + _ASYNCRTIMP bool has_array_field(const utility::string_t &key) const; + + /// + /// Tests for the presence of an object field + /// + /// The name of the field + /// True if the field exists, false otherwise. + _ASYNCRTIMP bool has_object_field(const utility::string_t &key) const; + /// /// Accesses a field of a JSON object. /// diff --git a/Release/src/json/json.cpp b/Release/src/json/json.cpp index c61740d46d..e5a6089aea 100644 --- a/Release/src/json/json.cpp +++ b/Release/src/json/json.cpp @@ -382,6 +382,41 @@ bool web::json::details::_Object::has_field(const utility::string_t &key) const return m_object.find(key) != m_object.end(); } +bool web::json::value::has_number_field(const utility::string_t &key) const +{ + return has_field(key) && at(key).is_number(); +} + +bool web::json::value::has_integer_field(const utility::string_t &key) const +{ + return has_field(key) && at(key).is_integer(); +} + +bool web::json::value::has_double_field(const utility::string_t &key) const +{ + return has_field(key) && at(key).is_double(); +} + +bool web::json::value::has_boolean_field(const utility::string_t &key) const +{ + return has_field(key) && at(key).is_boolean(); +} + +bool web::json::value::has_string_field(const utility::string_t &key) const +{ + return has_field(key) && at(key).is_string(); +} + +bool web::json::value::has_array_field(const utility::string_t &key) const +{ + return has_field(key) && at(key).is_array(); +} + +bool web::json::value::has_object_field(const utility::string_t &key) const +{ + return has_field(key) && at(key).is_object(); +} + utility::string_t json::value::to_string() const { #ifndef _WIN32 diff --git a/Release/tests/functional/json/to_as_and_operators_tests.cpp b/Release/tests/functional/json/to_as_and_operators_tests.cpp index c1bbb732e0..8b01ce9e58 100644 --- a/Release/tests/functional/json/to_as_and_operators_tests.cpp +++ b/Release/tests/functional/json/to_as_and_operators_tests.cpp @@ -312,11 +312,66 @@ TEST(negative_get_element_array) TEST(has_field_object) { + + json::value v1; v1[U("a")] = json::value::number(1); + v1[U("b")] = json::value::boolean(true); + v1[U("c")] = json::value::string(U("a string")); + v1[U("d")] = json::value::array({}); + + json::value sub_field; + sub_field[U("x")] = json::value::number(1); + + v1[U("e")] = sub_field; + VERIFY_IS_TRUE(v1.has_field(U("a"))); - VERIFY_IS_FALSE(v1.has_field(U("b"))); + VERIFY_IS_TRUE(v1.has_field(U("b"))); + VERIFY_IS_TRUE(v1.has_field(U("c"))); + VERIFY_IS_TRUE(v1.has_field(U("d"))); + VERIFY_IS_TRUE(v1.has_field(U("e"))); + VERIFY_IS_FALSE(v1.has_field(U("f"))); + + VERIFY_IS_TRUE(v1.has_number_field(U("a"))); + VERIFY_IS_TRUE(v1.has_integer_field(U("a"))); + VERIFY_IS_FALSE(v1.has_double_field(U("a"))); + VERIFY_IS_FALSE(v1.has_boolean_field(U("a"))); + VERIFY_IS_FALSE(v1.has_string_field(U("a"))); + VERIFY_IS_FALSE(v1.has_array_field(U("a"))); + VERIFY_IS_FALSE(v1.has_object_field(U("a"))); + + VERIFY_IS_TRUE(v1.has_boolean_field(U("b"))); + VERIFY_IS_FALSE(v1.has_number_field(U("b"))); + VERIFY_IS_FALSE(v1.has_integer_field(U("b"))); + VERIFY_IS_FALSE(v1.has_double_field(U("b"))); + VERIFY_IS_FALSE(v1.has_string_field(U("b"))); + VERIFY_IS_FALSE(v1.has_array_field(U("b"))); + VERIFY_IS_FALSE(v1.has_object_field(U("b"))); + + VERIFY_IS_TRUE(v1.has_string_field(U("c"))); + VERIFY_IS_FALSE(v1.has_boolean_field(U("c"))); + VERIFY_IS_FALSE(v1.has_number_field(U("c"))); + VERIFY_IS_FALSE(v1.has_integer_field(U("c"))); + VERIFY_IS_FALSE(v1.has_double_field(U("c"))); + VERIFY_IS_FALSE(v1.has_array_field(U("c"))); + VERIFY_IS_FALSE(v1.has_object_field(U("c"))); + + VERIFY_IS_TRUE(v1.has_array_field(U("d"))); + VERIFY_IS_FALSE(v1.has_string_field(U("d"))); + VERIFY_IS_FALSE(v1.has_boolean_field(U("d"))); + VERIFY_IS_FALSE(v1.has_number_field(U("d"))); + VERIFY_IS_FALSE(v1.has_integer_field(U("d"))); + VERIFY_IS_FALSE(v1.has_double_field(U("d"))); + VERIFY_IS_FALSE(v1.has_object_field(U("d"))); + + VERIFY_IS_TRUE(v1.has_object_field(U("e"))); + VERIFY_IS_FALSE(v1.has_array_field(U("e"))); + VERIFY_IS_FALSE(v1.has_string_field(U("e"))); + VERIFY_IS_FALSE(v1.has_boolean_field(U("e"))); + VERIFY_IS_FALSE(v1.has_number_field(U("e"))); + VERIFY_IS_FALSE(v1.has_integer_field(U("e"))); + VERIFY_IS_FALSE(v1.has_double_field(U("e"))); json::value v2; From 0446dd9e128203d14acff09aae290471fa64de86 Mon Sep 17 00:00:00 2001 From: deeringc Date: Sun, 1 Oct 2017 22:33:27 +0100 Subject: [PATCH 122/438] Fixing formatting --- .../json/to_as_and_operators_tests.cpp | 100 +++++++++--------- 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/Release/tests/functional/json/to_as_and_operators_tests.cpp b/Release/tests/functional/json/to_as_and_operators_tests.cpp index 8b01ce9e58..eb1dc4f71b 100644 --- a/Release/tests/functional/json/to_as_and_operators_tests.cpp +++ b/Release/tests/functional/json/to_as_and_operators_tests.cpp @@ -317,61 +317,59 @@ TEST(has_field_object) json::value v1; v1[U("a")] = json::value::number(1); - v1[U("b")] = json::value::boolean(true); - v1[U("c")] = json::value::string(U("a string")); - v1[U("d")] = json::value::array({}); - - json::value sub_field; - sub_field[U("x")] = json::value::number(1); - - v1[U("e")] = sub_field; + v1[U("b")] = json::value::boolean(true); + v1[U("c")] = json::value::string(U("a string")); + v1[U("d")] = json::value::array({}); + json::value sub_field; + sub_field[U("x")] = json::value::number(1); + v1[U("e")] = sub_field; VERIFY_IS_TRUE(v1.has_field(U("a"))); - VERIFY_IS_TRUE(v1.has_field(U("b"))); - VERIFY_IS_TRUE(v1.has_field(U("c"))); - VERIFY_IS_TRUE(v1.has_field(U("d"))); - VERIFY_IS_TRUE(v1.has_field(U("e"))); + VERIFY_IS_TRUE(v1.has_field(U("b"))); + VERIFY_IS_TRUE(v1.has_field(U("c"))); + VERIFY_IS_TRUE(v1.has_field(U("d"))); + VERIFY_IS_TRUE(v1.has_field(U("e"))); VERIFY_IS_FALSE(v1.has_field(U("f"))); - VERIFY_IS_TRUE(v1.has_number_field(U("a"))); - VERIFY_IS_TRUE(v1.has_integer_field(U("a"))); - VERIFY_IS_FALSE(v1.has_double_field(U("a"))); - VERIFY_IS_FALSE(v1.has_boolean_field(U("a"))); - VERIFY_IS_FALSE(v1.has_string_field(U("a"))); - VERIFY_IS_FALSE(v1.has_array_field(U("a"))); - VERIFY_IS_FALSE(v1.has_object_field(U("a"))); - - VERIFY_IS_TRUE(v1.has_boolean_field(U("b"))); - VERIFY_IS_FALSE(v1.has_number_field(U("b"))); - VERIFY_IS_FALSE(v1.has_integer_field(U("b"))); - VERIFY_IS_FALSE(v1.has_double_field(U("b"))); - VERIFY_IS_FALSE(v1.has_string_field(U("b"))); - VERIFY_IS_FALSE(v1.has_array_field(U("b"))); - VERIFY_IS_FALSE(v1.has_object_field(U("b"))); - - VERIFY_IS_TRUE(v1.has_string_field(U("c"))); - VERIFY_IS_FALSE(v1.has_boolean_field(U("c"))); - VERIFY_IS_FALSE(v1.has_number_field(U("c"))); - VERIFY_IS_FALSE(v1.has_integer_field(U("c"))); - VERIFY_IS_FALSE(v1.has_double_field(U("c"))); - VERIFY_IS_FALSE(v1.has_array_field(U("c"))); - VERIFY_IS_FALSE(v1.has_object_field(U("c"))); - - VERIFY_IS_TRUE(v1.has_array_field(U("d"))); - VERIFY_IS_FALSE(v1.has_string_field(U("d"))); - VERIFY_IS_FALSE(v1.has_boolean_field(U("d"))); - VERIFY_IS_FALSE(v1.has_number_field(U("d"))); - VERIFY_IS_FALSE(v1.has_integer_field(U("d"))); - VERIFY_IS_FALSE(v1.has_double_field(U("d"))); - VERIFY_IS_FALSE(v1.has_object_field(U("d"))); - - VERIFY_IS_TRUE(v1.has_object_field(U("e"))); - VERIFY_IS_FALSE(v1.has_array_field(U("e"))); - VERIFY_IS_FALSE(v1.has_string_field(U("e"))); - VERIFY_IS_FALSE(v1.has_boolean_field(U("e"))); - VERIFY_IS_FALSE(v1.has_number_field(U("e"))); - VERIFY_IS_FALSE(v1.has_integer_field(U("e"))); - VERIFY_IS_FALSE(v1.has_double_field(U("e"))); + VERIFY_IS_TRUE(v1.has_number_field(U("a"))); + VERIFY_IS_TRUE(v1.has_integer_field(U("a"))); + VERIFY_IS_FALSE(v1.has_double_field(U("a"))); + VERIFY_IS_FALSE(v1.has_boolean_field(U("a"))); + VERIFY_IS_FALSE(v1.has_string_field(U("a"))); + VERIFY_IS_FALSE(v1.has_array_field(U("a"))); + VERIFY_IS_FALSE(v1.has_object_field(U("a"))); + + VERIFY_IS_TRUE(v1.has_boolean_field(U("b"))); + VERIFY_IS_FALSE(v1.has_number_field(U("b"))); + VERIFY_IS_FALSE(v1.has_integer_field(U("b"))); + VERIFY_IS_FALSE(v1.has_double_field(U("b"))); + VERIFY_IS_FALSE(v1.has_string_field(U("b"))); + VERIFY_IS_FALSE(v1.has_array_field(U("b"))); + VERIFY_IS_FALSE(v1.has_object_field(U("b"))); + + VERIFY_IS_TRUE(v1.has_string_field(U("c"))); + VERIFY_IS_FALSE(v1.has_boolean_field(U("c"))); + VERIFY_IS_FALSE(v1.has_number_field(U("c"))); + VERIFY_IS_FALSE(v1.has_integer_field(U("c"))); + VERIFY_IS_FALSE(v1.has_double_field(U("c"))); + VERIFY_IS_FALSE(v1.has_array_field(U("c"))); + VERIFY_IS_FALSE(v1.has_object_field(U("c"))); + + VERIFY_IS_TRUE(v1.has_array_field(U("d"))); + VERIFY_IS_FALSE(v1.has_string_field(U("d"))); + VERIFY_IS_FALSE(v1.has_boolean_field(U("d"))); + VERIFY_IS_FALSE(v1.has_number_field(U("d"))); + VERIFY_IS_FALSE(v1.has_integer_field(U("d"))); + VERIFY_IS_FALSE(v1.has_double_field(U("d"))); + VERIFY_IS_FALSE(v1.has_object_field(U("d"))); + + VERIFY_IS_TRUE(v1.has_object_field(U("e"))); + VERIFY_IS_FALSE(v1.has_array_field(U("e"))); + VERIFY_IS_FALSE(v1.has_string_field(U("e"))); + VERIFY_IS_FALSE(v1.has_boolean_field(U("e"))); + VERIFY_IS_FALSE(v1.has_number_field(U("e"))); + VERIFY_IS_FALSE(v1.has_integer_field(U("e"))); + VERIFY_IS_FALSE(v1.has_double_field(U("e"))); json::value v2; From f301d1dd3dcc3aaeedbba75b8be21e33a331cb4d Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Fri, 6 Oct 2017 18:35:57 -0700 Subject: [PATCH 123/438] Fix compatibility with openssl 1.1.0 --- Release/src/websockets/client/ws_client_wspp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index 824d69a629..00b25c16b3 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -73,7 +73,9 @@ static struct ASIO_SSL_memory_leak_suppress { ~ASIO_SSL_memory_leak_suppress() { +#if OPENSSL_VERSION_NUMBER < 0x10100000L ::SSL_COMP_free_compression_methods(); +#endif } } ASIO_SSL_memory_leak_suppressor; From 253699c20ae92957a06127b641ff3d5978f18542 Mon Sep 17 00:00:00 2001 From: Adam Duskett Date: Tue, 17 Oct 2017 15:35:55 -0400 Subject: [PATCH 124/438] fix building with libressl LibreSSL is backwards compatible with OpenSSL 1.0, however it reports it's version number as 2.0, which then causes build failures when using OPENSSL_VERSION_NUMBER. Adding a check for LIBRESSL_VERSION_NUMBER when checking if the openssl version number is < 0x10100000L fixes the issue. --- Release/src/websockets/client/ws_client_wspp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index 00b25c16b3..e9e7658b18 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -73,7 +73,7 @@ static struct ASIO_SSL_memory_leak_suppress { ~ASIO_SSL_memory_leak_suppress() { -#if OPENSSL_VERSION_NUMBER < 0x10100000L +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) ::SSL_COMP_free_compression_methods(); #endif } @@ -210,7 +210,7 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: return rfc2818(preverified, verifyCtx); }); -#if OPENSSL_VERSION_NUMBER < 0x10100000L +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) // OpenSSL stores some per thread state that never will be cleaned up until // the dll is unloaded. If static linking, like we do, the state isn't cleaned up // at all and will be reported as leaks. @@ -382,7 +382,7 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: crossplat::JVM.load()->DetachCurrentThread(); #endif -#if OPENSSL_VERSION_NUMBER < 0x10100000L +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) // OpenSSL stores some per thread state that never will be cleaned up until // the dll is unloaded. If static linking, like we do, the state isn't cleaned up // at all and will be reported as leaks. From 9a4ebda8739c6a82ca345a8a07be5f420b836cf8 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 17 Oct 2017 23:06:15 -0700 Subject: [PATCH 125/438] Replace all uses of details::do_while() with internal _do_while() --- Release/include/cpprest/astreambuf.h | 15 ++++++++++++ Release/include/cpprest/streams.h | 10 ++++---- Release/include/pplx/pplxtasks.h | 23 ------------------- .../functional/streams/istream_tests.cpp | 2 +- .../functional/streams/memstream_tests.cpp | 14 +++++------ 5 files changed, 28 insertions(+), 36 deletions(-) diff --git a/Release/include/cpprest/astreambuf.h b/Release/include/cpprest/astreambuf.h index cf75ebaff9..d4769f7aa9 100644 --- a/Release/include/cpprest/astreambuf.h +++ b/Release/include/cpprest/astreambuf.h @@ -24,6 +24,21 @@ namespace Concurrency { + namespace details + { + template + task _do_while(std::function(void)> func) + { + task first = func(); + return first.then([=](bool guard) -> task { + if (guard) + return Concurrency::details::_do_while(func); + else + return first; + }); + } + } + /// Library for asynchronous streams. namespace streams { diff --git a/Release/include/cpprest/streams.h b/Release/include/cpprest/streams.h index 619c30d51c..823466aa3b 100644 --- a/Release/include/cpprest/streams.h +++ b/Release/include/cpprest/streams.h @@ -801,7 +801,7 @@ namespace Concurrency { namespace streams return true; }; - auto loop = pplx::details::do_while([=]() mutable -> pplx::task + auto loop = Concurrency::details::_do_while([=]() mutable -> pplx::task { while (buffer.in_avail() > 0) { @@ -892,7 +892,7 @@ namespace Concurrency { namespace streams return pplx::task_from_result(false); }; - auto loop = pplx::details::do_while([=]() mutable -> pplx::task + auto loop = Concurrency::details::_do_while([=]() mutable -> pplx::task { while ( buffer.in_avail() > 0 ) { @@ -975,7 +975,7 @@ namespace Concurrency { namespace streams }); }; - auto loop = pplx::details::do_while(copy_to_target); + auto loop = Concurrency::details::_do_while(copy_to_target); return loop.then([=](bool) mutable -> size_t { @@ -1149,7 +1149,7 @@ pplx::task concurrency::streams::_type_parser_base::_skip_whites return false; }; - auto loop = pplx::details::do_while([=]() mutable -> pplx::task + auto loop = Concurrency::details::_do_while([=]() mutable -> pplx::task { while (buffer.in_avail() > 0) { @@ -1224,7 +1224,7 @@ pplx::task concurrency::streams::_type_parser_base::_parse return _skip_whitespace(buffer).then([=](pplx::task op) -> pplx::task { op.wait(); - return pplx::details::do_while(peek_char).then(finish); + return Concurrency::details::_do_while(peek_char).then(finish); }); } diff --git a/Release/include/pplx/pplxtasks.h b/Release/include/pplx/pplxtasks.h index 516a10d4f7..c3f9552e35 100644 --- a/Release/include/pplx/pplxtasks.h +++ b/Release/include/pplx/pplxtasks.h @@ -7345,29 +7345,6 @@ task<_TaskType> task_from_exception(_ExType _Exception, const task_options& _Tas return create_task(_Tce, _TaskOptions); } -namespace details -{ - /// - /// A convenient extension to Concurrency: loop until a condition is no longer met - /// - /// - /// A function representing the body of the loop. It will be invoked at least once and - /// then repetitively as long as it returns true. - /// - inline - task do_while(std::function(void)> func) - { - task first = func(); - return first.then([=](bool guard) -> task { - if (guard) - return do_while(func); - else - return first; - }); - } - -} // namespace details - } // namespace Concurrency #pragma pop_macro("new") diff --git a/Release/tests/functional/streams/istream_tests.cpp b/Release/tests/functional/streams/istream_tests.cpp index 5ee4562999..63995fc8c3 100644 --- a/Release/tests/functional/streams/istream_tests.cpp +++ b/Release/tests/functional/streams/istream_tests.cpp @@ -714,7 +714,7 @@ TEST(fstream_read_to_end_3) else return pplx::task_from_result(false); }; - pplx::details::do_while([=]()-> pplx::task { + Concurrency::details::_do_while([=]()-> pplx::task { return stream.read().then(lambda1); }).wait(); diff --git a/Release/tests/functional/streams/memstream_tests.cpp b/Release/tests/functional/streams/memstream_tests.cpp index c4a0254213..1e20facf3e 100644 --- a/Release/tests/functional/streams/memstream_tests.cpp +++ b/Release/tests/functional/streams/memstream_tests.cpp @@ -48,7 +48,7 @@ void streambuf_putc(StreamBufferType& wbuf) size_t count = 10; auto seg2 = [&count](typename StreamBufferType::int_type ) { return (--count > 0); }; auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putc(s[0]).then(seg2); }; - pplx::details::do_while(seg1).wait(); + Concurrency::details::_do_while(seg1).wait(); VERIFY_ARE_EQUAL(s.size() + 10, wbuf.in_avail()); @@ -83,7 +83,7 @@ void streambuf_putc(concurrency::streams::rawptr_buffer& wbuf) size_t count = 10; auto seg2 = [&count](typename StreamBufferType::int_type ) { return (--count > 0); }; auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putc(s[0]).then(seg2); }; - pplx::details::do_while(seg1).wait(); + Concurrency::details::_do_while(seg1).wait(); VERIFY_ARE_EQUAL(s.size() + 10, wbuf.block().size()); @@ -119,7 +119,7 @@ void streambuf_putc(concurrency::streams::container_buffer& wbuf size_t count = 10; auto seg2 = [&count](typename StreamBufferType::int_type ) { return (--count > 0); }; auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putc(s[0]).then(seg2); }; - pplx::details::do_while(seg1).wait(); + Concurrency::details::_do_while(seg1).wait(); VERIFY_ARE_EQUAL(s.size() + 10, wbuf.collection().size()); @@ -150,7 +150,7 @@ void streambuf_putn(StreamBufferType& wbuf) int count = 10; auto seg2 = [&count](size_t ) { return (--count > 0); }; auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putn_nocopy(s.data(), s.size()).then(seg2); }; - pplx::details::do_while(seg1).wait(); + Concurrency::details::_do_while(seg1).wait(); VERIFY_ARE_EQUAL(s.size() * 12, wbuf.in_avail()); wbuf.close().get(); @@ -180,7 +180,7 @@ void streambuf_putn(concurrency::streams::rawptr_buffer& wbuf) int count = 10; auto seg2 = [&count](size_t ) { return (--count > 0); }; auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putn_nocopy(s.data(), s.size()).then(seg2); }; - pplx::details::do_while(seg1).wait(); + Concurrency::details::_do_while(seg1).wait(); wbuf.close().get(); VERIFY_IS_FALSE(wbuf.can_write()); @@ -209,7 +209,7 @@ void streambuf_putn(concurrency::streams::container_buffer& wbuf int count = 10; auto seg2 = [&count](size_t ) { return (--count > 0); }; auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putn_nocopy(s.data(), s.size()).then(seg2); }; - pplx::details::do_while(seg1).wait(); + Concurrency::details::_do_while(seg1).wait(); wbuf.close().get(); VERIFY_IS_FALSE(wbuf.can_write()); @@ -1935,7 +1935,7 @@ void IStreamTest11() auto seg2 = [&ch](int val) { return (val != -1) && (++ch <= 'z'); }; auto seg1 = [=,&ch,&rbuf]() { return rbuf.putc(ch).then(seg2); }; - pplx::details::do_while(seg1).wait(); + Concurrency::details::_do_while(seg1).wait(); VERIFY_ARE_EQUAL(26u, rbuf.in_avail()); From ba2e35b97e885707460ebd348b8409c0f83a0df6 Mon Sep 17 00:00:00 2001 From: Patrik Fiedler Date: Wed, 18 Oct 2017 15:38:45 +0200 Subject: [PATCH 126/438] translate the ssl error flag into human readable exception. --- .../src/http/client/http_client_winhttp.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 0a560d81c0..53841c0e1e 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -462,7 +462,7 @@ class winhttp_client : public _http_client_communicator if(WINHTTP_INVALID_STATUS_CALLBACK == WinHttpSetStatusCallback( m_hSession, &winhttp_client::completion_callback, - WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS | WINHTTP_CALLBACK_FLAG_HANDLES, + WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS | WINHTTP_CALLBACK_FLAG_HANDLES | WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, 0)) { return report_failure(_XPLATSTR("Error registering callback")); @@ -1092,6 +1092,23 @@ class winhttp_client : public _http_client_communicator } break; } + case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE: + { + auto *flagsPtr = reinterpret_cast(statusInfo); + auto flags = *flagsPtr; + + std::string err = "SSL error: "; + if (flags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED) err += "WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED failed to check revocation status. "; + if (flags & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT) err += "WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT SSL certificate is invalid. "; + if (flags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED) err += "WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED SSL certificate was revoked. "; + if (flags & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA) err += "WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA SSL invalid CA. "; + if (flags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID) err += "WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID SSL common name does not match. "; + if (flags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID) err += "WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID SLL certificate is expired. "; + if (flags & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR) err += "WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR internal error. "; + + p_request_context->report_exception(std::runtime_error(err)); + break; + } case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE : { DWORD bytesWritten = *((DWORD *)statusInfo); From c6cbfc475e84194be93b0555c3ed3ad7752ec656 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 18 Oct 2017 22:56:14 -0700 Subject: [PATCH 127/438] Add v141 projects, update version information to 2.10.0 --- Build/version.props | 2 +- Release/include/cpprest/version.h | 2 +- .../BingRequest141/BingRequest141.vcxproj | 140 ++++++ .../BingRequest141.vcxproj.filters | 12 + .../BlackJack_Client141.vcxproj | 147 ++++++ .../BlackJack_Client141.vcxproj.filters | 30 ++ .../BlackJack_Server141.vcxproj | 153 ++++++ .../BlackJack_Server141.vcxproj.filters | 42 ++ .../BlackJack_UIClient120.vcxproj | 2 +- .../BlackJack_UIClient140.vcxproj | 14 +- .../BlackJack_UIClient141.vcxproj | 185 +++++++ ...e120.appxmanifest => Package.appxmanifest} | 0 .../Package.uwp.appxmanifest | 34 ++ .../Package140.appxmanifest | 27 - .../BlackJack_UIClient/PlayingTable.xaml.cpp | 2 +- .../BlackJack_UIClient/messagetypes.h | 16 +- .../samples/CasaLens/CasaLens141/AppCode.html | 157 ++++++ .../CasaLens/CasaLens141/CasaLens141.vcxproj | 167 +++++++ .../CasaLens/CasaLens141/css/default.css | 97 ++++ .../CasaLens/CasaLens141/image/bing-logo.jpg | Bin 0 -> 6264 bytes .../CasaLens/CasaLens141/image/logo.png | Bin 0 -> 3923 bytes .../CasaLens/CasaLens141/image/wall.jpg | Bin 0 -> 493727 bytes .../CasaLens/CasaLens141/js/default.js | 173 +++++++ Release/samples/CasaLens/casalens.cpp | 2 +- Release/samples/CasaLens/datafetcher.cpp | 6 +- .../FacebookDemo/FacebookDemo120.vcxproj | 2 +- .../FacebookDemo/FacebookDemo140.vcxproj | 2 +- .../FacebookDemo/FacebookDemo141.vcxproj | 184 +++++++ ...e120.appxmanifest => Package.appxmanifest} | 4 +- .../FacebookDemo/Package.uwp.appxmanifest | 34 ++ .../FacebookDemo/Package110.appxmanifest | 42 -- .../FacebookDemo/Package140.appxmanifest | 42 -- .../samples/OAuth2Live/OAuth2Live120.vcxproj | 2 +- .../samples/OAuth2Live/OAuth2Live140.vcxproj | 2 +- .../samples/OAuth2Live/OAuth2Live141.vcxproj | 190 +++++++ ...e120.appxmanifest => Package.appxmanifest} | 0 .../OAuth2Live/Package.uwp.appxmanifest | 34 ++ .../OAuth2Live/Package110.appxmanifest | 42 -- .../OAuth2Live/Package140.appxmanifest | 42 -- .../Oauth1Client141/Oauth1Client141.vcxproj | 204 ++++++++ .../Oauth1Client141.vcxproj.filters | 33 ++ .../Oauth2Client141/Oauth2Client141.vcxproj | 205 ++++++++ .../Oauth2Client141.vcxproj.filters | 33 ++ .../SearchFile141/SearchFile141.vcxproj | 146 ++++++ .../SearchFile141.vcxproj.filters | 13 + ...e120.appxmanifest => Package.appxmanifest} | 0 .../WindowsLiveAuth/Package140.appxmanifest | 42 -- .../WindowsLiveAuth120.vcxproj | 2 +- .../WindowsLiveAuth140.vcxproj | 2 +- .../WindowsLiveAuth141.vcxproj | 191 +++++++ Release/src/CMakeLists.txt | 2 +- Release/src/build/common.vcxitems | 193 ++++---- Release/src/build/common.vcxitems.filters | 467 +++++++++--------- Release/src/build/init.ps1 | 2 +- Release/src/build/package_info.xml | 38 -- .../build/vs141.uwp/cpprest141.uwp.vcxproj | 91 ++++ Release/src/build/vs141/cpprest141.vcxproj | 78 +++ Release/src/build/vs141/packages.config | 11 + cpprestsdk141.sln | 243 +++++++++ 59 files changed, 3386 insertions(+), 642 deletions(-) create mode 100644 Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj create mode 100644 Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj.filters create mode 100644 Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj create mode 100644 Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj.filters create mode 100644 Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj create mode 100644 Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj.filters create mode 100644 Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient141.vcxproj rename Release/samples/BlackJack/BlackJack_UIClient/{Package120.appxmanifest => Package.appxmanifest} (100%) create mode 100644 Release/samples/BlackJack/BlackJack_UIClient/Package.uwp.appxmanifest delete mode 100644 Release/samples/BlackJack/BlackJack_UIClient/Package140.appxmanifest create mode 100644 Release/samples/CasaLens/CasaLens141/AppCode.html create mode 100644 Release/samples/CasaLens/CasaLens141/CasaLens141.vcxproj create mode 100644 Release/samples/CasaLens/CasaLens141/css/default.css create mode 100644 Release/samples/CasaLens/CasaLens141/image/bing-logo.jpg create mode 100644 Release/samples/CasaLens/CasaLens141/image/logo.png create mode 100644 Release/samples/CasaLens/CasaLens141/image/wall.jpg create mode 100644 Release/samples/CasaLens/CasaLens141/js/default.js create mode 100644 Release/samples/FacebookDemo/FacebookDemo141.vcxproj rename Release/samples/FacebookDemo/{Package120.appxmanifest => Package.appxmanifest} (93%) create mode 100644 Release/samples/FacebookDemo/Package.uwp.appxmanifest delete mode 100644 Release/samples/FacebookDemo/Package110.appxmanifest delete mode 100644 Release/samples/FacebookDemo/Package140.appxmanifest create mode 100644 Release/samples/OAuth2Live/OAuth2Live141.vcxproj rename Release/samples/OAuth2Live/{Package120.appxmanifest => Package.appxmanifest} (100%) create mode 100644 Release/samples/OAuth2Live/Package.uwp.appxmanifest delete mode 100644 Release/samples/OAuth2Live/Package110.appxmanifest delete mode 100644 Release/samples/OAuth2Live/Package140.appxmanifest create mode 100644 Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj create mode 100644 Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj.filters create mode 100644 Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj create mode 100644 Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj.filters create mode 100644 Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj create mode 100644 Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj.filters rename Release/samples/WindowsLiveAuth/{Package120.appxmanifest => Package.appxmanifest} (100%) delete mode 100644 Release/samples/WindowsLiveAuth/Package140.appxmanifest create mode 100644 Release/samples/WindowsLiveAuth/WindowsLiveAuth141.vcxproj delete mode 100644 Release/src/build/package_info.xml create mode 100644 Release/src/build/vs141.uwp/cpprest141.uwp.vcxproj create mode 100644 Release/src/build/vs141/cpprest141.vcxproj create mode 100644 Release/src/build/vs141/packages.config create mode 100644 cpprestsdk141.sln diff --git a/Build/version.props b/Build/version.props index b5eb1517da..13b7b76e69 100644 --- a/Build/version.props +++ b/Build/version.props @@ -3,7 +3,7 @@ cpprest 2 - 9 + 10 0 $(CppRestSDKVersionMajor)_$(CppRestSDKVersionMinor) $(CppRestSDKVersionMajor).$(CppRestSDKVersionMinor) diff --git a/Release/include/cpprest/version.h b/Release/include/cpprest/version.h index e197de4118..c91a3db40a 100644 --- a/Release/include/cpprest/version.h +++ b/Release/include/cpprest/version.h @@ -4,7 +4,7 @@ * */ #define CPPREST_VERSION_REVISION 0 -#define CPPREST_VERSION_MINOR 9 +#define CPPREST_VERSION_MINOR 10 #define CPPREST_VERSION_MAJOR 2 #define CPPREST_VERSION (CPPREST_VERSION_MAJOR*100000+CPPREST_VERSION_MINOR*100+CPPREST_VERSION_REVISION) diff --git a/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj b/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj new file mode 100644 index 0000000000..215c686f1e --- /dev/null +++ b/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj @@ -0,0 +1,140 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D} + SAK + SAK + SAK + SAK + Win32Proj + $(VCTargetsPath12) + + + + Application + true + NotSet + v141 + + + Application + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + + + $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), build.root)) + $(BuildRoot)\Binaries\$(Platform)\$(Configuration)\ + $(OutputPath) + $(BuildRoot)\Release\src + $(BuildRoot)\Release\include + + + + + /bigobj %(AdditionalOptions) + NotUsing + Disabled + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + + + Console + true + + + + + /bigobj %(AdditionalOptions) + NotUsing + Disabled + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + + + Console + true + + + + + /bigobj %(AdditionalOptions) + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + + + Console + true + true + true + + + + + /bigobj %(AdditionalOptions) + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + + + Console + true + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj.filters b/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj.filters new file mode 100644 index 0000000000..bb6411f159 --- /dev/null +++ b/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj.filters @@ -0,0 +1,12 @@ + + + + + + + + + Source Files + + + \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj b/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj new file mode 100644 index 0000000000..f06fd04ff8 --- /dev/null +++ b/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj @@ -0,0 +1,147 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {830b6e2f-9224-41d1-b9c7-a51fc78b00c7} + Win32Proj + BlackJack_Client + SAK + SAK + SAK + SAK + $(VCTargetsPath12) + + + + Application + true + NotSet + v141 + + + Application + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir);..\..\BlackJack_Server;$(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir);..\..\BlackJack_Server;$(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir);..\..\BlackJack_Server;$(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir);..\..\BlackJack_Server;$(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + true + true + + + + + + + + + + Create + Create + Create + Create + + + + + + + + \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj.filters b/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj.filters new file mode 100644 index 0000000000..d19e3a56d0 --- /dev/null +++ b/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + h;hpp;hxx;hm;inl;inc;xsd + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj b/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj new file mode 100644 index 0000000000..928d64e91c --- /dev/null +++ b/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj @@ -0,0 +1,153 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {84350cd1-d406-4a4f-9571-261ca46d77c5} + Win32Proj + BlackJack_Server + SAK + SAK + SAK + $(VCTargetsPath12) + SAK + + + + Application + true + NotSet + v141 + + + Application + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir);$(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + + + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir);$(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir);$(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir);$(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + true + true + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj.filters b/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj.filters new file mode 100644 index 0000000000..a13f88916c --- /dev/null +++ b/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj.filters @@ -0,0 +1,42 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + h;hpp;hxx;hm;inl;inc;xsd + + + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient120.vcxproj b/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient120.vcxproj index 97459a28e4..00535c0cdb 100644 --- a/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient120.vcxproj +++ b/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient120.vcxproj @@ -138,7 +138,7 @@ - + Designer diff --git a/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient140.vcxproj b/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient140.vcxproj index d38005e2cf..2a0c920c4b 100644 --- a/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient140.vcxproj +++ b/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient140.vcxproj @@ -43,35 +43,35 @@ Application true - v120 + v140 Application true - v120 + v140 Application true - v120 + v140 Application false true - v120 + v140 Application false true - v120 + v140 Application false true - v120 + v140 @@ -138,7 +138,7 @@ - + Designer diff --git a/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient141.vcxproj b/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient141.vcxproj new file mode 100644 index 0000000000..2479ddea21 --- /dev/null +++ b/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient141.vcxproj @@ -0,0 +1,185 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {b8d3f85b-da71-4aca-87ba-10fed681dc79} + BlackJack_UIClient + en-US + 14.0 + true + SAK + SAK + SAK + SAK + Windows Store + 10.0 + 10.0.10240.0 + 10.0.10240.0 + + + + Application + true + v141 + + + Application + true + v141 + + + Application + true + v141 + + + Application + false + true + v141 + + + Application + false + true + v141 + + + Application + false + true + v141 + + + + + + + + + + + + + + + + + + + + + + + + + + BlackJack_UIClient_TemporaryKey.pfx + + + + pch.h + WIN32;%(PreprocessorDefinitions) + $(CasablancaIncludeDir);%(AdditionalIncludeDirectories) + 4100;4267;4450;4453;4702;%(DisableSpecificWarnings) + + + + $(OutDir)\$(MSBuildProjectName)\ + 5C945ED108BF1723994A90F9BAA4B7D93FBE0E47 + + + + CardShape.xaml + + + + App.xaml + + + Player.xaml + + + PlayingTable.xaml + + + + + Designer + + + + Designer + + + + + + + + + + + + + + + + + App.xaml + + + CardShape.xaml + + + Create + Create + Create + Create + Create + Create + + + Player.xaml + + + PlayingTable.xaml + + + + + {198ED804-2655-4D92-8104-C220E3EA9452} + + + + + Designer + + + + \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_UIClient/Package120.appxmanifest b/Release/samples/BlackJack/BlackJack_UIClient/Package.appxmanifest similarity index 100% rename from Release/samples/BlackJack/BlackJack_UIClient/Package120.appxmanifest rename to Release/samples/BlackJack/BlackJack_UIClient/Package.appxmanifest diff --git a/Release/samples/BlackJack/BlackJack_UIClient/Package.uwp.appxmanifest b/Release/samples/BlackJack/BlackJack_UIClient/Package.uwp.appxmanifest new file mode 100644 index 0000000000..0ed116553c --- /dev/null +++ b/Release/samples/BlackJack/BlackJack_UIClient/Package.uwp.appxmanifest @@ -0,0 +1,34 @@ + + + + + Blackjack Client + Andy + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_UIClient/Package140.appxmanifest b/Release/samples/BlackJack/BlackJack_UIClient/Package140.appxmanifest deleted file mode 100644 index 45057a76b0..0000000000 --- a/Release/samples/BlackJack/BlackJack_UIClient/Package140.appxmanifest +++ /dev/null @@ -1,27 +0,0 @@ - - - - - Blackjack Client - Microsoft Corporation - Assets\StoreLogo.png - - - 6.2.1 - 6.2.1 - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_UIClient/PlayingTable.xaml.cpp b/Release/samples/BlackJack/BlackJack_UIClient/PlayingTable.xaml.cpp index 809fa4b180..a6bd90995e 100644 --- a/Release/samples/BlackJack/BlackJack_UIClient/PlayingTable.xaml.cpp +++ b/Release/samples/BlackJack/BlackJack_UIClient/PlayingTable.xaml.cpp @@ -43,7 +43,7 @@ PlayingTable::PlayingTable() : m_dealerResource(L"dealer"), m_alreadyInsured(fal this->serverAddress->Text = ref new Platform::String(L"http://localhost:34568/blackjack/"); - this->playerName->Text = Windows::System::UserProfile::UserInformation::GetDisplayNameAsync()->GetResults(); + this->playerName->Text = L"Player"; size_t players = 5; diff --git a/Release/samples/BlackJack/BlackJack_UIClient/messagetypes.h b/Release/samples/BlackJack/BlackJack_UIClient/messagetypes.h index cea826c559..325b915c2f 100644 --- a/Release/samples/BlackJack/BlackJack_UIClient/messagetypes.h +++ b/Release/samples/BlackJack/BlackJack_UIClient/messagetypes.h @@ -108,9 +108,9 @@ struct BJHand NumericHandValues GetNumericValues() { - NumericHandValues result; - result.low = 0; - result.low = 0; + NumericHandValues r; + r.low = 0; + r.low = 0; bool hasAces = false; @@ -118,17 +118,17 @@ struct BJHand { if ( iter->value == CV_Ace ) hasAces = true; - result.low += (iter->value < 10) ? iter->value : 10; + r.low += (iter->value < 10) ? iter->value : 10; } - result.high = hasAces ? result.low + 10 : result.low; - return result; + r.high = hasAces ? r.low + 10 : r.low; + return r; } BJHand(web::json::value object) { - web::json::value cards = object[CARDS]; + web::json::value l_cards = object[CARDS]; - for (auto iter = cards.as_array().begin(); iter != cards.as_array().end(); ++iter) + for (auto iter = l_cards.as_array().begin(); iter != l_cards.as_array().end(); ++iter) { if ( !iter->is_null() ) { diff --git a/Release/samples/CasaLens/CasaLens141/AppCode.html b/Release/samples/CasaLens/CasaLens141/AppCode.html new file mode 100644 index 0000000000..60ab734521 --- /dev/null +++ b/Release/samples/CasaLens/CasaLens141/AppCode.html @@ -0,0 +1,157 @@ + + + + Casa Lens | Casablana Test App + + + + + + + + + + +
+
+ +
+
+
+ +
+ + + + diff --git a/Release/samples/CasaLens/CasaLens141/CasaLens141.vcxproj b/Release/samples/CasaLens/CasaLens141/CasaLens141.vcxproj new file mode 100644 index 0000000000..bc93468518 --- /dev/null +++ b/Release/samples/CasaLens/CasaLens141/CasaLens141.vcxproj @@ -0,0 +1,167 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {FFBFD6C1-B525-4D35-AB64-A2FE9460B147} + SAK + SAK + SAK + SAK + Win32Proj + $(VCTargetsPath12) + + + + Application + true + NotSet + v141 + + + Application + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + + + + + /bigobj -Zm140 %(AdditionalOptions) + Use + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + + + Console + true + + + + + /bigobj -Zm140 %(AdditionalOptions) + Use + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + + + Console + true + + + + + /bigobj -Zm140 %(AdditionalOptions) + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + + + Console + true + true + true + + + + + /bigobj -Zm140 %(AdditionalOptions) + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + + + Console + true + true + true + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Release/samples/CasaLens/CasaLens141/css/default.css b/Release/samples/CasaLens/CasaLens141/css/default.css new file mode 100644 index 0000000000..65809e84fd --- /dev/null +++ b/Release/samples/CasaLens/CasaLens141/css/default.css @@ -0,0 +1,97 @@ +body +{ + width: 100%; + height: 100%; + font-family: Calibri; + background-image: linear-gradient(20deg, white, #DDE6DF 62.6%, #24507C); + background-repeat: no-repeat; + background-size: 100% 100%; +} + +h4 { + height:25px; + text-align: center; +} + +.Logo { + width: 105.59px; + height: 103.64px; +} + +.searchBox { +} + +.textclass +{ + width: 46%; + font-family: "segoe ui"; +} + +.tftextbtn +{ + color: #fff; + display: inline-block; + background-color: rgb(230, 100, 0); + font-family: "segoe ui"; +} + +.PictureGallery { +} + +.mainPic { +} + +.thumbnailPic { +} + +.CurrentTemperature { + vertical-align:middle; + text-align: center; + font-size: 75px; +} + +.WeatherData { +} + +.EventTitle { + font-size: large; +} + +.EventDescription { + font-family:Helvetica; + word-wrap:break-word; + font-size:small; +} + +a:link {text-decoration:none;} +td +{ + vertical-align:top; + valign:top; +} + +.verticalLine { + border-left: thick solid #ff0000; +} + +.wrap-words { + word-wrap:break-word; +} + +.eventful-badge, +.eventful-badge * { + margin: 0 !important; + padding: 0 !important; + border: 0 !important; + text-align: center !important; + color: #CCC !important; + font-family: Arial !important; + text-decoration: none !important; +} + +.eventful-medium { + position: relative !important; + width: 100px !important; + font-size: 12px !important; + line-height: 13px !important; +} \ No newline at end of file diff --git a/Release/samples/CasaLens/CasaLens141/image/bing-logo.jpg b/Release/samples/CasaLens/CasaLens141/image/bing-logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..22a2dbe521f7ca245a9652dc679d9d2235f86f88 GIT binary patch literal 6264 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 Ag#Z8m literal 0 HcmV?d00001 diff --git a/Release/samples/CasaLens/CasaLens141/image/logo.png b/Release/samples/CasaLens/CasaLens141/image/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1ba6835b106e61b45ef6d577554300cba86846c4 GIT binary patch literal 3923 zcmV-Z53KNsP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf4(LflK~#8N)!T=X z6~z|@a9+hi-a*8NkZ15IEXuNqQVPtNFawI131-Ed6QH1gV9o(VC8z}3`t_fWnz}nT z?9S}6|5Md9_s;F#gO+8*eP@*RQXA ze*XFAYJ|Cvc?ICFzy4ZYc;SU|`|Y=vn{K+PY}vA}U6V*Tl%Do_eY>cip;mHBQbpi1Px#BS((ZSjG*p z2dgB7u*?-ez|^qN)ja@WratbuzVpsIWzCv3W$oIvW#`VF<-~~-XJ+bO&N+amPMxYT z?%Hdwt#J+rM~@z@pa2KB;-dD?KmSxPnpgMr0cP0gJJ-MCjyo!w_wV07YccVh1Nho& zuhneIeFgu3C(Z>ln{O&$777TU04KFw8-sE${Z5`dS!>3)w@`r9Kz#Szch8R1r_3pUKoQ%*tXE%s zwbpjeKmUAPJmz8GOcx4J&thZZq>_k{9(?e@8c)q@4nX%IvkoAaQc}o>N)3#7_St7^ z6Z;gz7-zAreXztBiH*u1b4pUmBF2)b73f&GYuBz?0kkoE5}7psxsVK)(&VbEuBun{ zom!1saow$3w^qggP)zGfjFq_f;fEjAWMbYl8ULDVt|=>5uB`RrTW`HpzW@IF>Iu`4 z-T~yMpMCaOwKgS{6Pq`0F0Z`uN@d|EpL|l?${rRY_2p8Y>sx?`iT28NFy=R}!dsTc zz-OL$rj|Pr*}eDPTX#8(IjQstpt#bsHg@@LCm~^oL7G@6S;)HCP0R*>*aQr2oSlq$ zqleE}2h^8dda2xf_uaJ!-?nYr#96yH00F?lVvVLe`TFax&ngcjnby5rDGyvM^t-@6 z(^xbpjLAU8|MJT(>ztTq-ZZg~Vd+N~tbE{s2deSKNJaTL=?y@|s%)ot6;A?Olw|Sj zDAIg)pYor7{&{WgcS$4+Ak&-IctE2EMoDNGnYrDgo4)#CsC8`IxUn8kAc3()NiP5b z;r{#Yukp@l2sXvClup^8gwO={T*W9wv&C2hwoGFAVG{5#ECspwGiOr=O@GXfvFX93 z#X~MFW{*m4y#Ofis^^}3^2zEd6bCBhD4QJvNv)QvCRXXEf85T(rz^q;!_fiD7|qz3 ze{gPBzv;t}3xHK8cM5TZ>w0m$ua*wuStUtD&S z(iR9LiAJV-_~D1^HcJc@yk$Y(eRkUHfc1k9KB$HYFoVJv=Ei=^>ni3EHyKrpXfrU( zBRT|Ad|$L2s2c}B25wJWf1)ffBhl`%m7G)21otkNff z@rikTif}|P)rC;gCY=G~ZorU0NOKY5i0vBp1YTGc*ThKMDltznEfyX)aG<)5d)Oup z0Tlx!Dxez+@G@lth6yIcF$5h_a z5?}xo?XgcB^BdqWEu{vq1pXYZrr?$!jO&U4;*f;^6qta=N^WiA4@B&4GO;hAvo*-V z^lg()01`0^fC9h3ZvTjpNf1g9z+n?0fC3y~ak*xT$&gLJjiWIf9n2vnVj>Xpex-{T zU-oy%iWJr`Or`}O#RPH*A*U5wRc)p?wh)UDcgq_0ZhQ=-pUUfQ=IhUwY}K<-!XuJacEX0QQngE;;k9T`s=( z;u`C?tZ>rYB9a)f`Q7ip)ZexuDnPoe>Xx%A+=)+s~V2sl8sJ>=q!(8iTAQvhTYZmS-Wp}2Ej za{1+#m&J=0_W~d$op;`O^)#r9aBqMCP)tM|Ygc_}z{T)kI!^&mtTKpH-}ey_P{csW zw7G|}rdb~@Sg_#i=Omh?OP7}O&p*Giulc(+Q^7*(%}z$kF3Z*2vUD4WtpIuuh+Tqv zn@r-Ck#T()0BAt(D&n5fMhvum2NY^b)rSm?nf?sUZf8)Y04NhdeXanMC?t$Q83!O2 z?gK!EkeQV{;y;!p5s7~egLB#g$ib7DRsh35``kXI4HVzq9~Aev>nQ01K!Awzzyn&d z<##WZlsh&Rc4tkQ0w7BWoB%}OnN;V)WI6!Ol>lhm){X1tJ+`7`y0f5DuXOQ)bPA`We!17!UQ?qe!MHKhc z!q$vDfF4$jj0BJfuw2Aehoa)5!2yYp{=$m2Bm0qU@mvBV}@C^6V?{vb)9SDOYnS7SO0 z6sP=grz1G5Z0e)Mh|$eeKkg~Cm{ZbJ>p4`Q7r+_XD}r$^mnH%*B93ug8CpP9o#(v* zfGmvVBp=KW{~YIIfj^?;BIzf7u`p(1CQBQak+>-L#|kVlrg=Pzb)GS%lW3>V+#1lH z$1*WdKR}twv(d}g+!*kH3xG*>xi@Lzn+QPe)*O&aVGRqh8U}dR>MHh$7Z#N_cKWfX zcgI{mZsH153)Cz+&Hc2n4x5c(9`kBWO^l6Anq)#3Ndll;*A=sbB207UiRGF&j%Ao1 z;F@4s`>1d;7C;YYU{@0XP_n>C3go4YiXB5S!(uGV0x>a7ybu zzPOG!Mlo!lFzbsUS*V3^OYusAu~^M#Y*M7>@1tGQ#3*5aYv)=0eFvuIv&JBrrkOTmL3ZRED08mh31puac2;-j20?OSGrahSslqVou z00pQ60p<4)?!V+u5ODyuR}NZ$$nNRWfI43xa(glx05C(LtbglV^a9|&>@agAi2RYu zRr9Xy+6F`cpxktk2S9)}!0Q4P;P?5#`z&--| z2<#)UkH9_x`w0AxK)~4PlpD(U%sH<>H))iPldn6-WSANrF*8N!n&HjO@Y+^}W~RSO z4$I4;(I6_jyvHuP@at&f79b-lgO)`Ba%fpORkVt#EE*+;R#i|`m6Zno$>`ia?1m63 z`r2Qzc!J<>76UYvAog3X1ppGT%T@qzw49tQ3HFEe5JHpSf60eaA-{AWP#BO3{mZ6p z8XN%GlHIxqIi^wkRqmOF_-!BLT+*oizHS=zZy97m(rEtD_e(p!Yd=m0v=fpRzjrNj z04TekM%t?b41)&sQ~x2S{Vf;#sXqu-0pz!Ruto*YUouDq0R^yM@-8J)K=BuALsNL* zw?4@J6#cRT*`Y!N_X>UHXjF8~D@oWC+~6hZCZ9Fi;=JbRZy*|kv%GA+ADkUN1Ufvm`` zOb^Owp!Ti|o&zlefBjQl0kRppGMIG(y${gtp11cM0Od7<>+?-j$)6pd0`k+_Mj2N^u8>*}Dpu@C0tLe=woA4_y3JzFQ0={;toi zob->nUHWxhECj?VbypVj2W^f4nR{&kIV*8f;L6^09YNU!$llWz04c?K;MzZI=I_a1 ze~=sl3V&mc5mW^Uv|S$R7Z+9f#~0LMK-r!h8Bl)(sNB02*hVQn;Pzhmt}Fx8{I{(y!`6z*_ui%0G_)*sXRML>4R^-R{0?2>|5fmE~j=F#sCm zA0eRn?$Odp+w`zD{_ro2U!VV~Z0|BV0D%Ayc6R%T{;qF+f9@i+YYTuwcKhz$27Z?n z0wA8ir#~h8$9)9;^9cOak$%T=u+NKvXYa;#q2I^7xdJUGt71eW>Ugg(X6l&u@;w#Y zO$XhG1@WswZ~G_{^Ux_zozwpDgyyQL;C)Tr13yM1g!-xv^U5;F{tzU2*^$3J zj;)t{0X;7IvV<^oWYSy3)!~#C*Ki>>Muo$Y_s!?`G=teK6w=9$Jh2Y-P9hKLmm~a( z*kHrsX>F6DpS1K&+GgtN0}Q9)Eu~W6pWvPSL|jFAe+VGahAf zGy?Gop-xRNY4z6Li&YbHf0Q>)xX6XxvNK6ydb4Q@T|$3p9p5g#(r+cClBFqo>Uo|G z8b43#+<%h8$*hpn>-vaOYW-}bdkeNZBfd{pvrbJQG`QrgH?7}z#$}qs_<3V7;YbH~ z_x7Qk?BF|NZ#r{iD%p`^d=e2{(4dmA%c^5!w5pRDne{^_T6d$i52$)Ak4NWJWNfoaM8QsVJY*`$}P zjEUjS)X@*2S*PQ7ip$r}SW!5~E!%LZ+NNIeso~~5d(F&ndXD)sabo5MhmOc&Cgi9| z*omzpR&19V^HncjvF+b^7d`T}h{ss|g{a)dnSund=yNqnaPDwn4vXQ!h69gpFZ!sM z-n7&`|Fi40>Qo;h0q@r0Zgq)vXiodx0M$h^$NR?(FMNMGDBat*?2XpCf)TWSkwyM? z74-iG)OPa?Q<90@En|6?iA3Ck%U4XDcHWUoU(6)=2*uVQ3M)2!%pFub$F7yGC7hC` ziX5)EbMT4c>X*ag4`ywc*`2?R?)d%Z{LlJ-_Gb)XLiv455^CFS^e#Q`W#>4 z=c2s7{7(V;U+UC)``h3Ccc`k(C_NZ<%Z@gQsS5P}hHQPjz}FM$S0dF91%*mDe|XS4 zHQ1sbaX0wBquE7{fp^+-L$uL>7h2rR<=~2O2kctDoY%FT;oCkP;upptbEm_6T_lW) zvdgrhDJJ-2bwbZ8n!ei$Hj|4FU)^5vu)M5V+IZ=p)sfX3afvljK}3-!90G#eCJFVNH*yuZ0ybc6727N0qQWJH=A^c2fpt zKvxiUjrvg&Ed6wxVb#bx%fYbOPff-R12}bScnosLF**u5Qk~J+D@8`vQBKqdge;c5`SKBR=z6Sa~ z&n7sK`PrMT0O>>FjLWRIR2>q;{}1DzHPk!wpydCP|9_O{Pq@e%|26(W|HoeaM$UR+ zEr_|Ih4x-E@{qp}M8-bQg%Yz6K|2IK5NSE%>o8~G$i%pN24Y-Go zz7^Ga1bK6BF;>#QFEgU^l_W#Gu6^U7qkPp;S!aTJR7^Q$Zrsrzlkew!}nXIhnv;9G!dqj2ur*`483X*IXWbfxS81wbfa1DUvZ{AhTw~Tn*Ve?60B2rkr4Y;j+bwPheK)3DE!8 zkMrVpe)&HL;v^Z^Q);#|9v$~~Vdma*^s644yp#T7YUl2?c%GaTXgO*}wqVw*d+hbo zh{~of%(HJpGvxVf@_iqoFLeyvz)T-`06afm)}z~C~kDI^L=%H?=yHA`urC+mtTiK00k z-8TFevlkUVeDNFqI{S$^*LiJp&X4b)JOhzc-|pYV|13{HBz?x9|Bc?XU`s;Gfe+H4 z|IhFABgWVd+?do|1Y0<|&M#N4Tzb^Wzq|1MkT7_!y*<-VYv|)b^rf^$$X3dZ2paLB-Zu|!hm3juWIq9EWsywoFBFtnI$@Ex6hvUY~1o1QTTtHp5xRP6WsQRS92j z-iu`f#$WOOyRP;Z=eU!fFv`pJ7wnc46qf8R*e@$%KAntn{-Uk>{dBrNCEl8mP`oN5Ryk2W9nHGW(i6J6>1Fcsamb!wq|Bew0$7KAyW% zVsZC*o{*CbG?!2<_I~YnZTosau|m9NnOvDc;*%-Obb;rqO+??s^6q~Ad)fbt|IMF6 z{(bz{{d@kWN;f*3D7?d!CoXlBruX1+3S`Kar5B!jYW6Q~^y1$xNKZXTSDtvk@{Br(X2?e7 zdBy2teCTB^KuOs%VC01e41F@^oRo;R={-rcl>|GRuWar(%HfISNu=js;c-Dc{F4?Gj+sO z&7n2OzfK3KeBIpWGUp0ipb*c$8~gl# z&0ij%zt5*an=$k(baK1rXf{c!_(_(4OVQ`RRQEN-LsK{pjcx|&2f~NB%U2e!A;f`{ z;eq&7)(_{OwggR6yzy(e=QH;6)v4OrQ?GuG`P^&pdqXiD)bjNF2iDd2f#DQD9C2-N zrJVb)@B?awZVeCI)FH(+_tZeTV=e+&Pl~lj*++Y}CqthNWzeed-KRhB(mc`)YU3o7 z_x!F!$(?f_QBVLW#BTbF54gjhnsnGHG77xKnDMQ=x<-|h6< zUb(EA-*}15>VM++|KI!n7~Q`A|NF=PegE%||9>6-_s9SLg!SM4_}?G@`{RFq{r4Z& z|NHTOKmPCE|NVF8fA;79{rP`?{@Xe?I^D=lp-} zi4O(3Eci?mpT8HFd}5}rj{*+>n0unQd)(jtBLd;4SS*GL?_YdWyX1ozyouj^Cign` z(}H-ld%<_V-;N)6o+_9Uq1=XY!QW=+o*t}UTGq5nvBpR8A<^H@kYOMaxgJ_IT?~? z!JG^iHgopEt#SP?uN0fJEBP-yW6bd)UMtRi>929(lZ!_M12S;b4-)^5%=JhN~U-9I-#*odZOdU?lT$ZH}Q1+^SX1x z1(%ZCG(D=4uJq2Ty`CA0X|lX&R{i%g8R03~Z^|`jIkbW=Rhs4C^lMd-PaT@<0q96m zkqOdE)u~l6Vx

PS{hmg26{$T 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⋘pF_=#!XHsoBu_o`VV%AXCp;=DSYI%0 z6QB$sJ3Ur=tV)SZkp?RAxs&ePK`gYWN7=~XX3zS(=(K*=P<^;&G^VwFGgbUTv|IBG z?+(yjE4(m(4UF$qbt(4J(|Rr!c2+F6Fu6>dr{Wg%G2)cvqi3I8RXPU9h39IG-`#m* z-}&gCUvMimUrZfTe&%kL?K8*t4_f6FtU7{f=UYP|PsQJBaTSP$KbFzBtDqwXq0rfm zkh=PK)TaP=lH`DVbN6xe=vqN~$C+yPM^~R`zf0)gT~b3l6g0RQ$}2JH!11J9tRIhL zb0X+V_%9jjKCV)qQJ|7H?e%2x;2%g=A)80YoAjVq^9KCWBlLlr!( z_mbN4#1(SdppfRJk(}$1#jpd(5#>es@>n_*B!Fi@*y{=|HsRluM;TI?v#pNjMioKY zC$Cj9N%Pb*U=&Z73eRYGo#RwDS#w6| zzG`-IBcgH9OExq9^-EsrN}5oyvSnl4&dGwaZTdSvWHR`4g7Fx`@Ubr~8*{nPPg^x< zl!#+z%Nzig7mrl|iy_whY~+&3!8qV^4^*TJ*3f3!c;-ZQ39RE-(p4$J&zpBgZcQU^ z>IQaJI<>qHsbC7+DD}`-pn?TqHWsX3(Oi3xuP1wnCpJ&f-lsH*q-V=9)szqW)=0Iz zS*`P;&Q`R6d6HC6{*;wq*0^j>_2sIoW1}=p>e})`QWJ$>d#5$i-P_hYX(j;&RPW22 zuXTQ?%sRS&Ww>Y)<9IS#cIl^y|K|2>Edg3tc&0nA7DGm>Us`XkW`ON>dh;#c^Akq2 zO8pvT&bMco$kFJ6Z}*H`6CO09T!_;Jg{(C==KRJU?GoNzwfunIwwoi zV~V3SC4vaJxJE#PL~Izu*x2+H@B7!I3W=QQgT*pvFz8axrEkrV+SIM=Hka{eu{z~j z)NKH7$0M(YKQrhcA5D4#BE%ueJpQ=WnQD~+N}d^TncgvvrE*}9;7%umnZvH|Mo2tG z7PuSxkOD_aiPhQ4khT2$IufMa6pi*DsOVMAsS6pTOUMa^!1rELq|$nE2#lr5QiuUl z0mWW8>1`~>lkC4e5_^R;V`@!}Z+##{L;E8(sU^W_!6s(bCCO1pbVYlv=y>zn2EkZ4 z-4B75LK4SVW0vgG&fa&g3N3zK#Y1!wK4Uz~+%X%nbYhq>@usV}bz)~PBVw%tFZ=P_ zmu$96r#-{w(@v#^U+Ylm4WCQZ6TKofx?~qDS3!8*e1WYs@Q~jik3JR8+zq<%U6QB% z*=;mJto#N%&d*Fk7BA=Gfih0-E7qxh_tV_4?Eo#E=P-n#MKdGE9Ia|8jK?DRuW3JE zBcufB$>>2D*7Nf-;#G6a*oCBwU4xGw*dkgUL6EKN;7*( zdDKS9raj=Lh1wnnE}%@$(agB0b{Rl*A~%aC4Uh$H6!?NLXEL_u2?f;WAHJYOY8e$?I6?23o&94T*+)rcVF`RQ zs;HxQ@FPwAsPoerjY`9nC*?xb#d5dI!+XgLb#c;FQnUH;13AhH2dCa}YTicdEBY;)1`Ry<-$zc58m1)_mB@kF z?FzB4GESz2DDs(Dkn%h@iv-CoM=WvyYjrMV07I57ei*3#7DvgV?4l6#5%g6m&Wy*M zz(hLASNkC*3Ao&d;5AXti&@5YZnLO`4^X~0^9GQYAH9|+zMGB(v_dvZ8t0RTfSeZS z6``R4PKE(XPW9CuO-zm{j>6A0lBPvN|LA+u6S%F8_uUX`1ATjwzH7VYpZ=D zRgMQ#W=5{H>vVk%+vW;u56oluj&FeJ)#>sTrJ9XD)b3EY1rI-t1s4qq+7y`$TbIq5 zeI&>IO^>a>!29eKI9aY;!_HJ?Q_;kH1(iHu$?Rn%yaLN zGk5pL&D=jXb5D|)XOrwqvisfL=lQfnj^VK59`uP()`!-A6pNraFX}hc&KH^(NGppB?)$tK+ ze5kyRv6h>&{5@Iz>-oh3SbhGXLmic*Nr?1rv)DzI#%EDD0nVPbKrO@6gHnw+n7q!< zK#-1rfuEtCV3-%zV-+?!xOkxeC}lj*Xj=4DmrddtcW!++m3`vRT4uk63b*U#LclEB zd?7KcNoWc4^C_kN(~bL4jUp5J6A8&^gktCNt#Kw(n}(%1v8AWIQ&jPeAR4C_U5Gf- zhQ5}EN+6(ds@))zgOy+g==sBEvSp4eoj_PS5CR@AGJXxhIivi%;s3Gjms)1l`SY*HAt%ep?^ z(=P!pQ^rL>hF+}<845z~iG~6aa6o_I5l=5C-K7v`ZQ~c>*yiDs0gY+2UNYH$VqTkd zQTLMgclixjHmm-Sz{xKG;jr}1T$ka&tyje>MgZS7m{qPeB`3Hm-n)-i-uv4<@a`)~ zp86T$q$F2HA!bW_fR6btutQl}g34)UYRUP>}5@ zW_sLs#4~`#mF+1>t$qhye_X#mc_-C<5A;rgd-$Ef5ck_F*{f_{k_0B&dN#Z*wuwQ^ zB0&_7wB0?>F>nu1Dnzen#M}+}#WHCw=vr7Q_9+6o8mef$}@}@{DjxPhu2F!3dLMeLM+onSB;!AY9!U~Ck z_XYAE2<^N%!y-C1yO<`w!|0&)rexPa%x4tLml&yYT_F%mE4%$f_GtDVuv3?!BG*&{ z|F3;G`IQ3EJ&*~x2Ucs)?Hnjp@_1pwd*EpG9x|Jq%A;xyNw~kBq@FPuADD__FY4dG5G8{Lpvj8Gj+s0q7k6K2MEtE zOQBI}_S->A*tic$}jK)!4w)O+I z_XZq|%VioPz=rPaV6?(upfOidowY|`L=0Mr^CzwAJN|Uh9Et zCp!k`tde9BXZwVTuBE;&1b*ovH=mk zZB0&N^hvQA>qERQo1`P%1ku~E>xst??cd+Qucy?$#+xJag&2RmH7Z)>mB?0{aN7yd zRQsi^ufZcGl~)YiQkQsC{D{NUet(o3EVJg5EPwVaJmtmMHZ7$l>{hv|YWaFcsF@+; z0z(DZJtp!7C!E(ImXck(xZJ@IqkBL$ia*=Y4Q2|PO*pP%r}WG1WJOaA3(O7 z2|b;}irxWs8z|ZnZvRXORAv;^Cq^E&RAzKO_5alfvj_m+1uC@U%pMKhy4JkC-VncY ze$)}1bTJ}(`=2F4<7?vAA*{jHTErq|N$2ZMI1FkHX6mdGa1%U0La*KJWnnWFU-vK? zhU$9EUx*WMGjzF46x=eWIM8V<_>j=)7W9|GtHN274zZ6wDi8T=4HR(M^4CrZla4ntn zbA_|q13m`%Cxh5wJlKoi7_kb~QNlHxvptOhEiQU7?&h1v6Ka{{ty7a(N)t!W)`6MI z%2VTSm_&W zwBrUF7kfX&9=E?`(^sv!7r|Yhp3DN63OY=r#0TnVLbM%s1us-A$h^Qee+>_wu0}P6 z1_0g~UmnmqDQqmN;(HDr>0Cd=8;Zi{pz*8)DM9w4u*vV7%3g&!tj&nSY*`$+k7J_J zgBX&`8||sQ3n+v_(>UD&<(?h-_pwU(7Gpc0{(a4s6BYV+k#9rvFXdS#=~f|KcPXcq z=S()aP}tXJxv;W)xt0=ar%zy^5+NWTYUaT)8BQ+k$dQdN>C2@^d8F|ww+zQ7awd#{ ze=1ySoIqm&AQcNC#i6=ea_zaUwQ?3o*n`;QBRM1bl5t~qeQPXUb+CvT1 zhxe!ex2Z!g!ZUj!o)61jTsr8n9St=NJ2Jr&(lCU`0ohDOe5QIJadu?wQi@JeUE>L*~g+0pqD%MWA9q+>fl zRC57OCm1B(FNJPtch+dhL=?FsYT+=1C&8{6J7GdGo}trU1li#6eq_J^MtBm*UAt}| zkti+|j#gsf9>3ygdDG?K#DFPzjX=no;dh45#DQ_K#k>$T%*k1w!leE+o1K0#7IA(g z6bbD~=XwBq^^RIvR$f^}P`{!sJQa;53|B?7!)2g|h0-Aqwq~~>6$54bom28~v83;t z6+L8x+<{L0qcsMloHKYyQ@a3hoq5m4{ErMwWPu6D?4k=>fJp+*KEal~2+Uw}fb9kH}j$D|yjJa|W!Y__;z{x4LrM5*ELIDIV_uE%?O4 z0F)CJQ@_7Cd#8uCvt}Kqn96+Yar2$DBX-4S0|$G6v36%El-i6%_oL0oV(eOcaX2-T z;fFK@WZa?xRx2uSYDJIAmA;@Wn5vsGFbsSbfKtW%M3V1?)(5a~*ciQG*GK22$t<^p z4k5!!IOE!k@}dXPHP(`0KR)8%}Mbl=U|Y{3C+@eCozpRF0UhCF21cPAb;t4eG(yt5P}J< zS-}}RH5C0Gtu-N3wP+($EwAzw5G;>ErCVgv1bxW?tZijH9G(MmB4RD5^_)?mDQ|{qfpdLjZz#Y#ucca6) z81OAxnv<41za(Kej4^yAmRTL}RXtD_TnS@dtP-;6Jj*A_pgS*Q0sCf>Oie;l(3lf4 z!7Ou{*zIF0$$0PZtLdVCuWu?7TM?h(EB23Y&t4<(P-j{Cvfz^CYOQLm-mv@|1LcrI-xein)6ZgTdkM%f0XKseE%=O0 z%x!A@0hc!uBHulJ|svHY-+1v%S7ymiOK$LMI0t&*_g!DnZ9n+DJt5(8)gQ`SkCu7ZwXzsKxSLBA*3kKR4r^t3B%!pwDJC8 z2YNKL+x)Zm;h*Sz!j3(>JXObf>}{}pf%J0 zXcpyc}#_O<-}bG;n_BEjQFJ$$$spQ8|<#T8TBScC!~`XOa|oTPG3tP8y>)Y~S!w*EJF8nFmoE ztAq~Zkq6@1FNr;j*!JUxkXV=xADhe1=l0ud>4q+4Rqkf$`T|u76vCyFFcQq%GFb|_nDYXr7$jAfhyEf}^WG^0 z@W8n(&I5K8Lxs9L;D^vDVNTp*d6ZE&#NfhW+T`-i5fDSkd{4Eh#lSiwk@23_`oFyR zuONyX27{}g203W$2hOSe9JxiMtYWc!fBFvS%iE8&agEP>s+HQ3vOx-0CJoVTvdXlo zINPOMTm4vk7R-L1I18Q<9rrGruklhQE#PxLaSBOV;3}j@CPX{!p6TvCe(0XIM|!BLBS%` z71ecfKV<^;&-iedmG|D<`Hca==NX}(k4rR_5bwRSV%0bjB3nhqsr`)uk2x{86c{>L z%1dp&vAjw;h#C+gtbCKoO9CPv>7D^`w)!>STCM=cRdTEHApA0 zKPnMJ?b_0MVM`?FaAJFlz+=@3rLmc}l*HKR=mXw0e*i)aK>2T;L^?}-5)B?d;pYK! z54O1It-O!s_;Q=nizU7-2(7~Ady`f|ahJyfCwlB9x0kFc6g@i_Cm+AefNUAmEZNm| zFA~5_Qm8q!(<>++;7;o2kB!AtNtD6elww0qU(Q(*$p1eqgT17V_0g7Nw`ExM>(Dk| z)Lps235}k0JZtQO)}fnIr^M&|Chm+h#nhcJv+pa`5ez>#YGFdXASzDl-=5M`K80d~ zEUq_9^$&$21h80wvgJAob#Odn>ap^^Dq+)KhhnEXpdf&P_&8Yo-3EL!A6Nrfh5C$Q zE~1=!3)w2t7@kb=U?wravL0B{v$|m(4^JbQfkH1T1o|*g0~G3gt%C)-rfQL0&R48G zD`J+HBZvJc8akr_Yy;7$N4*nRSJ{@*j##Vl;K%;s{!&xe8kDHFMPfMf37hh-pnSXL zXGKFWGDoZ>c!U!)4&ajcmklPy#bG~zWW90t9&r!r!~z$8Cp zbJZVNL_B4bEW=c_~58K!EL%gezUw z8H{;D2cM@_6G`*v-RJSOP1*!+!-7Uz9-F3Go9U>utnf>*VznIBcH~b6UtX0A=_n`eLB->nAP>4U%bhIq#f!1~FW8m%A z7F1c+W58GTvEYFm3ABngv>tF+nrgnx$GZ-K=un+K%Oqcr%udpY{GBkK^lFj$b}NyK zaT^2RW%~4~lK2hGB=*{07JKH^_lm}Ydr}~{yefecjeG%vwq9X=%Y&#=x&|V=a7}d$ zI4<>zn^}2~SGDM}>gp?E@|`=UbW396t4;|I9>E;zh?v8(ewB7fp=buC0@*0ZMI0)i z`C#xy@8HsXJaGVPkz+4sDw^PgQq^WUepFK|@(5}Mq(Gf@_yQed&Z5<(Xt5)Q*TTGK zg|H}})Z1AKc`O@t?3CNl4Dq*@+tfQ^u5DqQIO6aGD-x@b$je7^1!rPKuU&)}%$6!d zS*aqh&;~4CKUN1uiODQB{tXD{6j+~aoVf-+2q+iC z;xp(U@sp3NR}KlJj72x7tw{HNkGkmRzsa^uav;47zr@aCvmd$^qZ4NZ=VG(5F+sz} zfYJlGsHcHgYLWAfSY#@6h0+p;V+;+5DMhnvkH923fGIkKpqYx$aVZE#gKZ%^DJN8D ziTQ{afYA{^JcbUrK)$PbTysLeK}Q&x>aJvB5=$A}dZXX+-{JoUTE$N?5Ilv}lc1FA z>p>h&UDTB9$qno)9%vD^Y)}4zw43cibSmx^Ka&v?@PIM z8hKv)AV>$B%Kelp^Aflv#uvg|T$mA>i!dEWtjxZbLSaMrsT3G_F7x7HcH%<`eQeFK z9qpwMPGIPelP(_**3OF=X08RHeb(>;^6}9aN;RXUSU_n$@0@cnk7|+@E$OK)QxCF0 zs?3Cw7Td5D@d1_E!$i{lMW*ZuBDM5dD$=B^DeRY^In&ICi!H(4d)bRW^Y;1EYy?<0 ze-Od`IdblYduhqxTu*&wqXlk|@;2e@-m`O)TVbTr2h*T8(`!xuY6_`pQ^zHLR>*%_ zJCjGIghSq+!8VgfHip%a3ak(9h3iFGD#OqFaLBnt(;fDv#CNVI)v#ZOjXe4@#gT1H zLTy_YE!;CQ0w!N(w)j^hVZ-u*67M~jTny#^ecgt?su*dQ$8sC^1H-NyqCccb@3G%L zqrly}^o5Q(Ad9tn)O@FUdc@LokN87nJ`zXU-vcUdCH}H1ApkMhEDm#(?lXhRqD%9( zcUpWc{ZqTx$zbiC(jjjiO(f6f)~htgBj$A@+x{;tLpqZ(f=OG!T|uX$e3i;l*U+}3 zJlSfnx&rrsLr;IFsFw)z46R;yT*(PFe2}OI)})C2GJm< za`0nodL(5I`2aON8=0vpOiL^u&!o`W_uKmq3xcR}wq}Qf@kA_p9D0>a$UBZ-_$jQIKrA)=GUe?>bsjO04*a#>v#p)xkuwzDz6^uAcOpjPIK6emX(o*0dINht=LH{FD@@m+7_x7jJJhCYguj}`g}}` zPbgZFZ5rb7Zb~Rx%xZFyR&N776Grt=@?VakFUtgA?L~OH%IMXmKg;(luX895vx zCv4F#p2&G%th{Qaqv9g%EV%L87-S zi)0hHnuq8T_c4#s=xi3Vn36>f;v3VF=Z&5l`+=#%Is3oT2%cjFC7-;Y`-n$-+pV*&8w6OsV zw1@B9=&*4B=fZqSg*t0M8PL500es2C*r>9kw}GMqxfo9^csszWQY0$_;lx^OSJ~9Y z)u;Q9osvm~&`rjt5}LVb7x7UF5!i|AsZ9I}2MI77j%#_tgnd^IzUzInag)FPIeUyb zPj4rm8ehSB&w%D_(S>l4E` z`G*eiBxSY|NfN3g8Ji3FyESE<&hxD?*kgAYZT?hK5HXPZX6P`4+gKqexk(-$l}2?-*C5{eX`wij}mzH?ne_`Kyp1u&1-=m~L;o($?{ zix(&SSRh91uEJGkOFu@v#PwfGY7yKf5w40& zey)vcxf0(o+3WeG|)arJ|0f|@QHY0vlRvHqZdPQfX56rsC!+WI{+g0e_z_XEMKo?r9F9Pf$@f;`>e3PND94&dREyH`$@) z7=-ynd{6wc5)1v9m`|}P>UJ_dXo7!@?Bmqch7L{_ZHebXcrs#^wg{tRz(j=52-$}d z;=|)*DIrNld~->k1}*{jJvkb<3q{nzN>LFEXYPfYl5n_HYyQw#f;+NU*G_~E{HJ5Q z;4Tdp9o4tGEQ3|!>6WC{bz@hmdCR)Y9+^lzamTw&`bk}=609VBWg?OqnVB9;L z)`9w$lzprTKsKMsTZF3JM|PZWjL)L%4_)fU4;+j=&P=B$-WtIu_}`mP47(kcM9%2o zr^0wN50%9w)8ue+n>ltOz-jnmP4yK#Nw(x!gYVHC!gzFJ9&CdG>?L%>SUE;FGEZTdf(07iDgr`)pXUh|aoiQhG$wy{HWZohM zUN+gn*4ndGR%0bgQay$gN&`%$TnUPk*|tK4kAugr1D^V^ZL!BP_dW!xdprIVQ4h&+ zsH=r9X8S$s*PpXc2^(BvBAfbEPGuy97xMEIffV)=bncBNuv8zUx&-*{xPfL_Hq0bR zjZG0Vl=BFh;^#zDUg=}e4x1A=aZH1z+A6||G~Uba(|iDQH~eIWOCG?cUttJLx#-MI z^7`s2^y~;~XKTd*RV;ENwv{-1Kmv-^q4kw^%F}=%hwcG3xk{^OrZhg!9X*o+c%##8 zd)X(AElh+7FXuo59}QKTUp^7m7IY5+Smd4AV{F|SLR9z}Mc9-=CG_%3LeZ_yPph}KOOcu5yvng->~UdY7ULH@TtJp=HCG`1 zGh^n1!J(aG($}k1c=(R_INu6n>VZRPCr8=>rh1efmNFKsq;yQOCJa#fds~O>IyuL-aeip~5;~2IAxf2p%$PAmmbd{_ zdGb$~7d$V%_e(kz9kcdJDSdec|t$%8}j^Srxx4r zkx31!WW(6lA6YA}H*bUp_SuX)iLzn0RwUZ+v1M%DxqfVI_qNGA;6kQBR;8p8$_+34@jzIN9le3dI;0cj>9VyUshpzpOfP zd#YkmFN-`0W6#HN+-|1dp%6f3u9m7CG5oAhfa|GhW=Zm}%B7u@A-FyWBT50w-u!(9 zy`KjRwbT@~F;N@<%l}IcYycBri%Cbu)e{#3Fg=3*`u|&Q^nanr*#E`yV!ne(82%rx z|GkHcNm~Bjng;L=Z~^QvKS%>`2R;B!fH!7|2eYhz`NR#d$2>6Y|0dVDZ2W)bI+xA- zU*|fPt^ChiXLhasbFTCMWvVkKWcdHkuyL^eYq*%mWE?!)|1y(t|4UNF$HV(CZy28l zpMZc6)9~<#h=>S@{_Fp@@_%b!o`je+{`>U*S^FQU&VWCV|No~t|9>~t86!@)`9H>d z{?EYA?_siaNAs)y3N5K;eQIKusn%wM$w6=ANgLu&@v#f`S`Wzi2^~F7DVhbM-^G2~ zbhvvkSsnT^nCvQQUHi)_aho5_#}9jW&5b4-O3^R0_*-7&cf^*zLcg>1LqdMqy)k{Q zV0>WEvObtrbqCH^3PxJgwa!DER_kCW>Xe?2r!HWe(3w2EX;}vt)1qw3-H$&*FJnH4 zFe&^jf{o5JyF~0ieF4(t^lRP-uedb?cYAf(y`A4R5n_(~EP5afFLi&`)Yd!uq6Sj6q%{@x#&B7wO zX?m-dEBIvVLYGCs4|INB^4l}MQocG(UomTHdivH)M`eq_km#M-T*$xqYNzR1=d7hG z5!RA7PgmGYttHdKSrWcgPxV@|Hn*HEQ|E4+qZ`)#!C}T(c~Qb6By6Zt877q8agJXo zWBuO-T4B;B{TGsP75twU{YJPI2#;{;-AV{;NSbAb3AP=6i?unTaT9LE-y^Q{zwf3e z+sQTeup=75d(?cX1eW$7EA zt4==|K2j)5*-R|h?51U~qU_63LoR3>cA+HL&dAY3xAy?vlPl;wfQ!B=^8UbJcF}Mv zbTweo$l?4foYdn)?CRJP+Na+SV=9_4lQVf`fp3JNwY zx|-?=6=|T!b}O-0i(eNoOiK%M+)y!&`{z+ZUr&>kNEZ9EYb<^{Q17mz>+TZA2^=!9ihE7~& zTO#epF)EKBjava*;)rnAWJl->nt9bso89tNLhTRV_=xt(N46^|VioJI$62e#kKiZO*efuQs|7LG^j8a0|A6`|iCZ`uuGNRCR(>bm zT*=qZcw@NL;HVSJ4*^a-AM_KH!C86GYPyEk^vil%q{IQSQ=|%b^se%d2e3023Bt@@L17S-K>4 ze}*r*EYdUDDE@tauE}8##rvY#b<^}+OVqT08hwOeT51ICLqZnF?zfZPI?g41zaLda zAGP&!jT&Q=Z2o0Bz;Y-8eX7&xTLZfI2MhD&x0;>*Y|gDvwmf^1QP=T1p~yIWVL`L@ zHLh2Qej-t&FHcRARtz8Q6GH#~aqj221nO;#F20QzPC{Ob5axNU>mg>^LFJh88I&P7 zxX&k0071$=@Yf@K3}!X8RgIVUP+k6EGe}TWlgYEpWFfhm>JdziAJP-OAgRkY{wgPE zwnVGId2}OHxFs?e#lV~)OkK6B@R*0@8HT;R=14Z-%Yv?qPlzNxjWgni?%fvOI!gJA~fo zt9iI9O40t3hO=j-+s@wW*+c9o2AmN|iJE1C0GoPj?y_n9(6K`&^@1;*iXDH0X)5|k zohMD5xvI_Pm41n_Ek9_830_Q9$$81n{{~|0d7Jfq_QXEC($Rk9;9L7-1Bt(-D&eR7 z*MCNz;o9>V{bu{W;yS~8 zT3yY%D}3kZu+Pm)kqV5Q$#o?i<nB=go=n=>%oNc~{=g}rOsmh;&MzZ3-yyqH zlCSmzJg^%3mRtr$-tQhDO0QweYfe{2GYZeC2u*Buy=%q6?c)VTMAL5#8?#Zq$D#+C z@FSWlc%NB%+6njWR*&RX)FYL|uHjuKa$X`G_E78RRGO{PCbkDlp-`UuA~L7*xzm%B zpLN?IN@d{gSNDKD^T%1Eg_j2$aN1y;Y73Suyja&#a-QN10eONfDZ7qsNjf5yBWAw0 zDHs*Z6>rAAv3rP+nelJf!V_~Jz0e7vDoK0qF1ikw2J<%r0c5!Csg|pB9G9AA0Q5IH z;Y3i||4EGg&!#+84Tn)vksp9n3LP$E_h-c76x94UCc*V!2B}%!j-H&X>54w=vsfJJ zWU*tnjCtBG-!JMRM}6Ee37*wPGCX}+F7DF$B?098IspIchmhjuNZcsXwKww=JdhUB z=oejsF!{c~n2({)=1dpfIvH6hWKXLKerPC+`uklhUU8VlL)3@B%|lgBnsB1$yhW;(y2~Tv;x}3Lo%hC#n{*qd=&5RJgesHJQTOop zzzhF#m6?ml;5*go+1FMBISnqB#UB+o0_@yQ4;+^wr15+kpPjyFF>-C+8!qET$S;^K zT@Q*T(uOv8X3;p>8}fPx1VZJnANM-&|8u8vlzAA<^&u#W8o|P@tNdm>Xw8R#NsEB` z>hCQW+^xNNrC;f9ypGskghOM%$H|se-Lt})>M!|y=F?3kS5}_6{>gAK&)mcpp?E-2 zZ_f1V*xy0VNjkP1mM$urwwkco2#)XI^DlmRAj@#o+22$r^xI(iS(`4;aecmuy_;0q zgEDM}wJ`0BdMfJ`MW>UOeIk!v`Q7-oes^lBv16d|Bf(1S`L0`!zMEHMwK5#8rt!P< zlF9oD$zW$1Jmnr%^Hy_%K^w}dQ0~tgXTl2Fg;FTL z4q1M6?kkxqYtqnZkmu4`9QSmXpS~%`78xHIuPoLjwUlC_P-hOqk_UzBy=oZ_BNWF) zc6*5ALgFE*$0k;lRSE(kDXjIWZQ@fdDj~anMEsdK=z&aHCIpG9=NZ`#ymEvz2$fL z(@?k~{`aNSn<8i3VMbm%ekF#BO@GfPzg-!+06&(@#IICpJ3UJ~-vfof8rhKCv^KtfuA|Y)8VVEkDdQf{#ze3E!o@>F;{8 zUQzW|T!tq&NxRZY0jI^6!W`LK!{hVkBvoc&XWNObV^914D&czP00bRM!Ja3JaJ!m_ zvloK>ma-{^Q^7CGdM4#BT&*YPXDAqwiKM!{$~aXQX;&LQ4=ztT#e5qbNnh ztG>5Nng2SV?dA7inLqYTChqIWhyO0_0h7dQtt08bBmA*+)=!NnnEJA9H*KxZcQR%= z8}a+6&ePs$H*CYMZLTkJwB50OL=({!ARj$MIMN#8%l)Q*9XyasFO>votw5=$J^g!b zz8F2tE8P5WMOEZl!J0v$E_{ltEeAEvf`>a@?ismdo(ZEEZLwTVU}-(sJkM&sWgM6* zY_~^3Ktf^g=Xph5g0YEUVkDzqUv@`{*QID+?(#?vafaWD2S6)zGU0v4Z}Gv|o3A9K zI@sq|Wz(Zm5j|C7>jOPPSzaRDL^W}H4u)#+BlD=r-pB7VQbvDN1eBNFjy%Z$QS^rz z?t3RF*L;jjwR2>O{6mj)ek78(X!)B@`-vu$WhjNXRi2|*d;^r|o!7E^4>ZtBaFR?24d(w>7A)%GFJ$_+rosPno-uvF92u@2$Fk$;aCe6EZ+zW>4-AHPy>~}@Hz)-O zXWtv`URNDwcc;>MlRYy*5$mYUg#(suSSGO1TT1Iu6=f}vz5BLb6isnL9^K}*CQGq; z_154IZ&kHx5d~NL%&vG78)#F`2otw63p6rda*Z1*^I$jV&NT>a+Su@=Y}Lzo_{A~i z5_Z-uX?zuc;RctB+Pqvk9<>Q5zQ~D(*uLVeXirNm$$=QEcEg{)^>>6a)HK`@Hb}FX zPgm*f3i~y+G~pY1^{E7{fKqHadm-#nVpP zHufvw%}1n)551fElQ9}<6uNQ`9DDkGtg5G9{Rpia_~=9adEp|zwy)B^#86ac`(i^t za&ewr8*gm)kWzWFDTNaB?rGdOIAfJI_`_AxiP_Qc$!edb^`1tv6T66ro^X4r#vJ(< z10rVbPb8hNU^{!d*i7hDe4@!ZIa)w1UHY*q_hv9};oh4Cc#-D0xa8tMvN*+DzXiy3Xk4BRC*>Mr_~@DD zbu+D-rI6%)P-H-gvhz-v1wb>D88*dyjfjYynH8m|gIyI*vI2IGp3fWWx?NtXHi;jB zil(bCZg7U;7@myBFWRe4S|SkIxfFv~nZH`88BZdDD3kWZuOBCQWr&t+jhCl4#F;d> zggXVilX3w&xX?M`zSo*(_xH2uv}1~K5-xl6jdUf8yVu<+mng|Nag+!a${(fMjpofN zk?`956-2ZAsOp?E_{&T#yXqR4uV!gM-r%7J(c2lfw?Ju*8%n0M0Y#0_?_Gag#blz@Yj{#*<?-?6 zej5GwO0nk#@%w-kyK9BD(I7YLH<9l^D`8P^d-?FvH=e4*imMkVdl!XQakt7~rz;ih zmJwUhxC z>VxT=4MYvCenpA!Xf4(C`)uXs&W_h{j0Ii+hjR;|+Zemj-j1%t?qJDLf1fH&GeDM) zT*BNK$5=S<5|8OdGMatzkfP zkP%!nI9crI{SWLC>hKnGD;k`pCb#F6(-Mqw6|$^6#k; zwFg6NHGyBG;}X0lJMCd4F5fS8IFpO__?`>Hc2a!rTiAl5(K|XYi4}vhnM!4R0(bIw-2s{ z2UEq+<52rEB&cP5*Dy`FT#46Y-n4Q5@6iW4-`v~-2bZNp6m4BH%0fzXoq~emF&?N8 zn|=$x7Pla6bCve)M+SrbaQIt_oi`H?Y`o6Y9i7*0m6eFKGj3ES5Ulc-2lrh6g7Tltb@3B1$Yz|l`n%%@V5+yzCwC5{& z;?w<4IO1PqFWbsZ_=hr3JB)bnhQT-myRhW2TQOTpsYLP~SnRy39lVMI!#Yu4?|}x% zF~N(VE3fjhGXH{qZGJDGB(aAwG_mlit()zMi-&s0+U&hmK?z+k9%m>(w!~1zw@MZk z%jMrrgBhK-q&|>*{ma1;8{whk_s;A5QBE%U?Xk)0PYk)KFOZ$v2{pm2x6J5q%cs*k zC4Z}Aoh#yuJteNSPxd3giN8}8T-?bOL=&0c@}gAUiIkP1rzA9c%M$7> zR<^&z;MAm7dw2D(dB)F+pZ%DlRj@d5-@;5SoYV^g?5Nx^cbmX9zDs+NE(YuCTo7aH z%p7@fn0eANAem|oIu^eN$exGI$gX|v#HuNH?TT}ed6oM;!2D0&;a7Jby4SW56#p)E zcJdmgxKwqW7~Vo;*S?@hQ}$OEI-8zga`=7>yiW*OrylN&q$slqCR!+P92^H2fg0vn z@LDqT=iwJn%3I8idKE0tFG8}ZvUZi3yiD`5EPrU|X#9D6!Pn4z%{Qu+r@m6j?pGW% z`^(HZPwqN=7CpS1$JRBa1;W-6I~Pse^M@|r3F0T@`$V@gJG$gQLYK|lYDj-IjgUvZ z@cS?XfSota8L_r8;XB-3DVJ&SW-W1??~g8-%)z$|C{SZ_p17=wrryET^PkmME$5e+R=PsdGR3bs$18Y?5 zcS)hRJx?9(s@%P{YY}Mb^DW;pjBWXrEHtm@M|G#|QTXdjo4bmd;KZ(o6`WR!H4l}e zD+B|)w9FrG@@=@sKdoa-q0;G^j5k)d_PVxYCd*03t1yCle!X^~kAAH%Y9|@#X2H08 z^Dm|N&|jdk%Ep=`=-|^BXvOFlYXR#f6q6ki<-@P!lf`UrY^oJt$Z!HZE*f+gjr&TQ zl!ymeaI&$|uzt#pacX-)OWuB~x;0mE|5$*vv`awpX8i$PW7XnL~v_9880!M}lYH^%a0H!_Onn>(Y0>4k*2 zj8|FJIejxd^s&8lX^s*m(QOLox(+Ti_a(H6j5pb^^2~{^B758C_lut7>r2WvSE9ei zoateZ%hzg)+=YC~CgKa$7@9iB&EQ{$aZEoH_P=%4?f;evBZ&LVjPcX>y)Q`vZYB{8ms4m@mr z3;n`k`h5ER%0s59Q43OmNBvNOr*Dkxu9%PAw&t{XM7Fba!`-k|%>z=UOl7Q48McxBg86CVf$O5` z?|}C!%*PgZny~0kBM*(}FO9k_0A(#L&q1m9NL=G@wC3K3=Z0Tqp5Y;)r07D47q&&s zf`sb$ZG5ic1(QE5{#?b8fp-ckzm2k_$l^)3XxQgp=0w^;Y*?Z$sR`vZybR)oM@cAlkW82W2;^tlMof0gsGolO zTRv}b9cs&+OT4bi9SHr0NT_nEB;2oU{rx1?>Sq+rF8Jo`Usi0{SFZPQ+^>-Gj^ght z;2fQLAp~ycivuNP5vm8)bs$LLunA>Tyl19>Bd=Sv$(^%5O4ttd{+u=YI0Tvd+r3Iw zUb2pBt9$)urx`BU4&0DIv<9a1;$uuj(n_3l&E_qY@kYB2mYHzj4kv74vX_HmYipqJ z5vNYFgC{4-8NW`4#}}l!-#7g)?7ew3o9o*z9@SY#HEguiZD=_+1P3xBNU00Af2=|wT2`r5oxtiQxX(GBt4J){l4#ee#1Zeylb6x z&RRRmBgCC&xN>=}&;7YR*L~UUi)&OWTX_9*#s`)6+}}?CDdyjBM3X~jpM;AXRxWrQ zR;7&(VhXoUoe#R9_bB~nv6g53sqhcS^3+t+?$|8My2bqQbo-V>cSPi2qXbXu!8WI; z>c0Bu@;py>)YqI(L<5Z=#;ouC{V|b*0Kv|q+_c*~CmjupRYlCo8q&<7eulP?aKV9w zT8hgxq)_)vXWDF`z-k|=r$~K$`>Auc%SP0JfB8Yj@WAk+cJ0S|&7IHW`fbIUDHvLHYa|99jC}F! z&pqPrd4!v&vh?nSvF+R=&C=m-uN}C36YKp;*?RY)&7+UK99{IT^83`{?6$Ax^U^!)GV)ImS}dhlSFfsK0BYTo25 z=28?W^M+MOW+nX0G0?{9Yai+`YH<;RCi%hnFrAJ(g*i|VIspLFg8MyN$Zl1on zN?dJpammv`Q;Qf(U~EQeeUm*pWWM*gvHs?oiqj`9zJLB;zA2_ls@T;j%HOqUqLzB$ zvtydicGPKJ?AhIJHm&W0gVVl&@X(TJ2JCj(4n2-pwjPgNX5eG54tn)#I_h;0JyCD| z!|gBRoS|3!2&Y5G_OoGLqcB}R8!(CT+gVT8yZ7fwPn{;7DS_`8{JIux_vb*HV{Y%$ z99+8?`zq$}1wzo!i>kLsqx8zDQ|?wfuYkFk(?)3BL%lEjRX*-}y;aKARBP4dY*b~g zpZi@d{*I@Q!M!`r)7 zZ{K>jC|#^E-xnI2eY^F{?PDz`-^gT>BBX2&*-JfCkUsNut$*NTMO{3*eC*w1nwn`B zB`0|3os#KoV7cNyhyBGx3YzXvn_tiLY;xSTlJsq<&Z>B_I~N~VEoZgg+B`~Pq_G$K z%`2xcT5Z?n3`?LVtH*;6X6*oKyf069clRtG^F4USku<1vyhI5oMju>V7*!+M8?bUh zC$@XhBSF{Ji~a<;{wbYgrSU$uv(P&Jrxo9=6!52cWZ&C+eE!!3#t>|-W;W07@q>$s zE+*@5Alm&&GIuieN*k`h%crxZ)&dGEN3UJLgjSw!P*NxF!)L36H9Xqq`}E5bkbIfb zsLzFB*Fs2Rf7n+Rlt?Dfu=Jj?W)-`nfSz@5$JiWSfL0 z%i62eGACc${jH>XFX-pF`E0-J@ny4kum-yDPIa!OR{@ zmA#dnIGR!NT98Md!XNqzw(YtqRrI)+Pewx^Tx~iYUZY4egP)V7p?z2 z0{G2L?ce7T6&0lybxIE%7N~#n%$YO#Ck*rr48Xt$aCi(V;(9a~6|Vm89bEJe_YH&J zjDVw2M>ckN{RSEnVWx(`!2L`Dt_K+2@bfbS-?)Ct4}9{Z-*xbHzf&i{ey2|P85^Gb z#USA14YhwC-p}_xkA4#q7V_7z{e1QPL;R8csEBaD8Yef-+0WM`0v-|K|F5$@7ZUN` zJNpp$#`{e|uA>6Y)S|&aZ~E()kO(#N%h!Ybk6cD$;NkwdN6ueI1q7JtZ(Lmn-27iZ z07nMQ49K}m_5bUX{u=T>8RTCl`9HnzzsW*=|Mi*tpJk{2$BF%at@YO{fJXv0{!jk} ztbF8u!{eWW{4FE@W3GS9^|vhWw+8>?UH_QtZ&~1P4gSZw{xR3zvcTUO{Ev72W3Int zfxk8QAMg6dTz|^~e{1kR-t~{U{+0#)*5LnT@A@we%pV01Ur_+V^@9bv00N5cHokxd zPyY?#nq#*Z` ztem{u#!jT9f%k0QvSZ7Z9df&6cFX)X^q zOwefjEj=bN|hy1EC4XmrN##}Ve|@h@Mw6W=DMrso&FFD@+$S60_Hu1gBI&i{D) z>&pIL*R_A6q;vD;|9fllR#Q6fr0e=%qEJ49tpt|pzH3u@%g$XL4D@HrD0NOjqWle` zxo-?@^Rc{xr})I5CiAojx!R0(^Si7OhrYA!fHo}rc+4iKP+&#*ie1Ku2tPo@ZpG12 zFUZQJniGYlO(S>xgXkT=Iw}4+9bt2QpM$p%bC9_bCB+r$GHl6W)5bN_lva&0CTXYAb4&QdxoJ+DysiH$rhc6KzjZ&}rRWW{d6M8sZW1dpF(n+#4I z=W!;0qP}K%$+tdlo4V-8?+zIbVj^BAo|P+s`Ut?WHZR34=jjCVm*3x3O!u;kyy`^3 z*?@#T;Vph*f)Vn>yAv`u)=)AHdjzCNUYRJ24aC&qB{Mo$c@*M_jDuz8p;;IAYd=Bg zp5KyxfGCnd(#^wqbCT*3_NZ6)-p7rNMvMRmk^?9n`w@MGuL(D%W#Z1oonpQsnO36z zKuTte`#h?r{7A>^$i}?IcI(fqR~hVAB&EEcR42TEg%@f#uUyf@Uv!;j_4b!gZTz$S z&=fMCj$N^@^tvJQIwSJUOtbBQ;8JY6cjw{XDx<&5uCY7EJ3|e4x!J~CK(Q0ru@sC7 z@|qg8co}W@=C&y*bLeVxc_eebzUK!>ir_(P*Ks7K013uy%>-(DYA~>_c(Ayp^b7u{ z#rA}b-kF@YW7m>Zx|KYAEqc_j^FDmW%_#55QDjShv=`tt zvpw&UouUFNkK{WWL;Jlx+V679tl=|R z9{DR|;8Z(m$_pqnsb<`s#eb%nnQB=`FoQS@f5jwH{Afr_$fgx(aE9>c+eUazn zLa*6vORvEo>e>;P)))r51qjI0)nkYPScz4tm7HtR+VSb)ySpfeIt4Y>VkvsCz{+Ej zHtjLJ@)!aHDKAOMd|7z8vfuFp-qHJUN(XUiHE7Ru8s65*Dn<256{8F$^I$EEj0l_? ztncwKNCnmb;ugaSU7pHoOhNpCRvG>^W8TwDjdwQ&C`c7-y92^+4|KKWH4*|r^aeL4 z%gg#Bo*324IKOo|a;zk;9Zt`VI`}dPk|TJN~=tf&}5Hs}E~vF3MMl#y{KF zOLwY4`N2?}OrlKoSP`ONdMiFzBf|NVOR)1cT538h8J6=n33|4M*yA#va{CJLrIj_T zW(kv1^Ntc6l%a-qc43zK6E5Fj+uE_=+DXSBPgL|v2bCl2K-N0r5#yG3$}Nbo)lazhZP;VoVd8A zwMqH7$gJ9^Um9Tq%e=Sd)O&VcR9UrBBEoL7K^D^1mONv*l|ulV!E1@2_lu96c}1Hm zhqSHwKxYtERnt~Q+xQjKSYy#3Rvu*ZCy}WomAG^!aY=3sctyS{sGpz;@i&`KomFk}A8rXxq@Va-@I&IxBFgG2_4@r$HDw zr>mRzmHetHw{p;>g6e7dZVPNX$exlCMzXOM?4n!dOV(^{>rR8Jtxk457p`t{vO3BH z!6KPRdCj|W?bTXGv;g~sEmkYeIKX0Q3T6naikhKi+8&J*dKkko7m-JBzt648u(1ie zsRSjdKa=le^+Jih&qQs*x+M`-`8`Lum2{by`#n%H*zf8WA%d93EX%Y@&Tn_M3^qKc z?)s2^z|ceEGRN>dUER>K54y?4qbi^(x9W&eb-sA&@l|PIJdsU%e0AIShld)rb!v~* z>J)>K5^a2Culh%?WqdqUC%(recqi&WdVV^^`EA(`P)Ui29w!@E)%z~&pVX< zmGkd8uc?@thbGy5e|C>Ufrv>8@Zi{2G|Ay&_qL_EI4ED!u}5&jzXSKF$clxDXNxP2 zc60S<`V)~6*}O^&gneLkls+@2M9*@~*25Ub_+zu#Lle6tgTsBwyW;Au+6q+!bz-Wp zFINA~`nC9D5zA|3$<=U!_$Sv0E%!yNMBtth6I^0s9cK31Yws;o8o2yfQ;WUG7~-D- z9WBO*C>{Rwr=QK~jQJePP$J>5eVfzClGVD2H*d_sw(G~65k4s7Q^IT0CRX=K2E{y5 zoKd?V6S zQCOyr02|wggl^R;>EfaGFZ0p4i9X`I_QY{I53LY0#9MZ3QPRtr@Zr}3cWqkm;k`qA z!ZF(Eptj`5^?`06JW@aTtV7P*nLJv5yT8r>Qx$&j<_9Te8Y!|neH|I&r)a?b+3Q zaiQdBvK@O{xBVB#T_e+(=9Ph1wCo$oI%!o%p4S0B8~L!Nv zWA0Jb*8Ex$v3~bgMV;^3bwI>qO0>t@FrQaURq8Epl4^Fdy54Z=4^Rs1!)LD6?7BK; zSF%o@Ml$9={KLK$Cwvv%@C8Qpg((~zLAdAP65;#<^t@wXSmkrBuAvSbrIx07sl+27 zHIm^k0aJNyHt2&-M=f(+B4OQAIqs0<*$9b7phN*5_fgGl9@&Roth(2Md4qI2TiSDWB}=ZNww2 z+mSwa^hK4At}Z*Pzm=WE;=Hg+re^E*O%58=?qYkC} zubp-$W3I)<}Uu5!W#0r%W0{@aKI5xLV z4_~phId<^q#SnFCf-uL(ixsRcI_j7)1|B%e^OtCoFm*rin^$jK%2;0K=zxQO)<+&l z&E9?2)GiJ*Huk6r5iVNq$#;TKIFp2#vMSadn0O?+&2-dn9>30Y`>T{iSW9X@n{*DQ%F&_-r!rgA@WW*Zr8 zfHP-wC*t{)I&SYdO+Gw1iRs0;;Rj!Rc#|&T!-5r526h=M-q~>H*g@4U3(Y9C%enoad7b83OYE+C_x=*n44OyM z^f_^dwN#2`{7F(w33FPYx=o60YU7)voU5|C;DLU&_R6Pcks1KTKrPXZY5Y?EN$yM5)?&({{iu6 zrN7RV_o(vF$|6{ek&fVc7mNKWT!J=XPa!Y%^{F*a`(E923KC=Dnl@O1pxsue%BxIV zIshrTluyt+Q=R74Ysu8A=yxXoU5+AZjv&>Yhm^~<4%oKlRBg(&Qop)s2#8#Jm*GUh zU?vd7Dt>@=gG_RP%W~O>Xh;BrTm~Y@Mie>zc{?KD5Y_mlLK&-7^4&ruxaVN005We^l{>J(oP_F8)e7#Zzj5E z6*Vk6Ij}8dU2;lGqXv^SIRY!2*231ZEfp?gmmp9js$#%$i(DFDKSj*Ryn6@?$N)ex zTb;wNpoot_!vZTkrX2{y42;dmZ%$GoPuVx85%ujru=JH`-e5lPRvwWFI=<-4s{+BY zV}~FJ2!M3lLaQT(d|?I9qJ|oh)|8|BG~`jER)mEeMVY3vSBMDuVkoOi+I1I3yq2?Xjlz>o#kyXm8D8wOls2@aO(4?pYHw}C>N6tX#XW3$Cz48) zRG+PFYa0DX;;C1tw4G;LIFyOB;UA#G1g|c&gr(${>r}SIEW@DM^R_t#BC6>VA{-6; zF%jiK>7YN z5q7`VD>V3C_4VZywN)rza|D?x6`V5f zb~hpcM%SO!^NTLXZSH2ljD0@&OBCuIkb4HlM>HOb@w;m4rLl4R#>RDeRzk(dN|dXu z-WPk8Os-o5#rz9aK}_wmtqX8?ul}l8_(Yx#7HBr-5+LRtkbIPYkH^kK>c?l&PQBR= zdr=kASdbM)tZ$*RS372)-)*WVBT;LvnFyHuDbwbx%DyJ?JvIpl5ZRtKD;b}szFs&e z2;vy#>vavGg>GV|3wiXHKP&Gp{zCjI5M*-`x8FcFyoW@`O^iOI#y(@I{)AAzMpoFT z*;&x`fs~yn02=an8GgGP0*;7FWvl75cz=$1*|<(o5wWl-O|z&nzqF-aJ`XObAZu$U z$6SF4d?U&J+K1e9+Qm>ClLXIkh1?aC({oyQW@yoM#7IoQ}MI4)+;og5O7 z)^XiCJ9Kw*aY=LK1Z*s!Q1IeF-DEzn`&5avw_9yAO5ltodUj1TheyEN?#yKbjTRr?I3#wSp?NOm;|0{mB|)Ig2GrxnwXfx1TD zc>xd#lL9yuTRi>8120AAblc&4KQ4jYR+)wis{!T>&Gl`zHpJkbIFT(wOAq4VA%P?}iy0OD1LpTb^-`DP zMD{N>KW**KdL!~u5f}1F2`Y2AW`!T&h||Ffh6ddS+{V>1b_(iDdaG`iY`s28=<_f4!ClPynSWt}{oO zZ!R^yB-s(J;zR8S&Q90ik^Cxp^^E0?W*nMPurpVyZ)U#$Ve2VTD>Yal77nx zmzQE?hO7OX)ej!o-K~L6IT<3(sR*m`Di9AAi?-(rcKU+toAY|0w({~vnQ0v`5KML&p~(`wVg&D*$4{u&QWNerv(yqHO~J*68*(&jsS3lg)|UB?Y$4NwT@l z$Wr9NR}F{c#7}4;%S9Ko0FGhX^~WyFLqS>q7}>rv0YDrHdee3eG|)s@skp`pA)~<& z*pUvImu>rNmTi1>Go^W;HMjLH0+f@I1`m>2bcu4Q0b1k@QCzW|SBi=%U83Tg&S|7x zfjuf{O;TN~7@&@2VL(Quh|E0NxYXs!0avN>L(o5opsU1bbSx+%i0#00B5js-Q6ZS* zk5z3h0T2v`m}a{%PX}pn1eePKigu{B8>Df-04xMTD-Fc0bd9TKRY}nR7_n{Wc$D*1 zDaQ(zNhxUhcxejkFZAO@oA#Fjt$7iD;}1;&1c|mKMvjU3_h;`=w9N$$z$9%mDlBT= zr3zF6Sj}=*1+UTxKup%moKgfRfa&mrCRs!lZEqfQWx=&UDJcmCNjn{gJR-7a+cAU} z5m~*BT_go9^M0J_48YzD`X9q7023B1nXK|ZKyXxq-8RqGUaZRSubR)s+qFTo5|?1m z+8$N%M72T*d&-`I1lilR=2K=IiZU?qNqKnM^OTI|IduJrs2to6~^^32VFKI3B~Q{zk3n7zIBw0rOQD;N zl4T!xC4Z#`d-QCX=q%6U#%dyZyejn|?j#{5T7&NYjQD^haLgOY=c0w!b`RWc4aR%( zY5pjFT?fKrXmPspze0Vob31sdZR8a9W2?WfcWK%%_0;+D%)UgdVXm>h$k5G!k=E98 za4wwm~Q^@|p9AT+p& zWjIlAN^g=Su#yOb!2^k^Y!BwkrnkAsR5ZkYtQ070gwen%}xK9(y?_Du)qv>1ei>xx?frHpWxToIafpYW`MS5Pc}uQ|K&M9Tri1 z1kg5K&~@LzkVR3!uEd$H=)K(?Hw@}H;vI-LxbX*N6p>M7d9qsogK{eon9R@8J3VK- z)%tIogU5yAN9wzqqu!O%sjUE}^1|K2;2my^lr^W_c*bh>G7yBd0j00;^pW-RS~gWM z_wujG5T@B57>I{TaE0JA%VF+)Y6U`3=sYubdar)Zp2~nigGQic5I|OD-|iv5o*F&I zJk5HS80p~|@1ifFr+rpEV2g<|yH~BoT4yQw)-u zCTx7M00c#nm;oDT>&KYw5nah~R|#O(Q6hDIfQUc@f8GC>7gn!w_uH+-rN(w6SYFWJ zsQ$amx=E^lw2Bqfyz|=YHnjLrALZNJmZHcy^?at~2dK3ch@8c4HkDJxH(A~V=9t?a z`LQ+$`rXu7J{l)kt7(4vVZz&U+6ak|I1}q-QL8E|*+X2GQ~gV)g3pEWRxyU11s_!d zF{2G$>lErI`)iW&!-XogN4_JGKC!jG+cnmUNRvh#s{QJoEG!u=RH1voxE8U6JRSW$ zAd|${n`$omwz8BxMLEpIMa~3{;>7}-!1cY^9~T#9>Svd;39?*>N1}((di_^_pD#qYcxA{N=^^+Zm7TmM# zBltZI-Ka5|*`v;1T^2KZK9_jzj<;5x3iUo;Vw?EB`nyIU8_gfquZ2hLt}+`5)vXnE z_(+bnI(U#|()M5cCcGpfTeqw5d2BIfIaqCcdg3R=o(!d|iBXP`LX*~euN&56(dnlb zCq-mDHcmwA5$qZDEV0!Hoz(%d4UT+91uj^xSU*2}Q{%Bd3cAk?^WYO*ll;)$fEe6> zr8HMh?$=!L{lfEo9=q_Nbovy0cu#Fz1GRgG9La#L22bt1Pi^M1AF}TE;ot2E{9_97=16T}B0LBb-`DAq{&Ii=b2|US+h_m_mG9SKRkTsEHw!cIZ z2pb(ED>kBEqr>0y1y)4=rhK?bjR#kv4)~*&Jy)WznCe-l#n`SXM-T1Cr*`c3+U{>* z&`6tR)ts>kV*=;}B2RIxp&RLO(>R8XD!U+th}f=knw_iFOS=pr@jHnirk4K(FU?8> zW|&$f)d(i3BE4eNhyDI{7^~E@@f`~ypSV1&vE|;c1V#(>r+Aw=&aIHKZ=Q5sZHDg|0XD58#y7|mF7 z-9@V2EUPbMr@+)hANsK;-Lww?lrf#nKA4|UJ- zlK=zp2MutO;+p5yGnWwUVgtYg*J**g{H%l=N+FzqZPLDf`w;0LZEQl`5E`%WL;r{jy=+Lk__E5UMCrK|p8d{ApHQCFqO2^-{?@y7S0odAx70$Dp( zfD|+USTTSJ1B2vTjxQ=0q{M-ZkswVYTwWw|yONbjii~{h5TmqOp=evZUB+1#ZL4y% z0T^upaVxJ@Dz7A)AXPU&AA{S6?)j6?5qn4@a(eg*9O%q6)zN#DVqn^gq_A zhE~g|EHj6K%~ppZ+u|TO1=Sb6SywBuw2j&2(>^OUr0NCOHU4UI^K^@hRp?GuSL=@R z>$N@WuGTE#>$LgyLmqjBF-P(+3vbvx>pqy8*9dr`IV1ioMsdwDA{8|QABr`LC8R&p zZM%M5{xx*q`Q2tBLc~1!12m2utKT17ee^im{LOjR1>-r!oBJ{0pBJBu?O0E}znbG! z2=opQ6f?`!e0(Rd+gBQ9d56b79W6;FPvCM`k{Rd(sT$5)l+jE7<~e$F7~5z*;keu^ zo`B7B?nzFYl$aItZfEv_Tjl*%QEn^Q9@tcI-VEl_SI;Wa*|YFjp>|WPT{plKOmlKG zf}VV+oX$)62z&plrwHoxXrQCZM$!%N1L0%lbL=}ec3*HzxpWLF8aR|sZL6h5wty{Q zlsSHRVASr>;bn9)G&QPsX5Ee;^g##>Hv0#Kq-6eGHC5tRab* zfqv?6!9K+`KRkhOgE?<3q_#UUOck#iyof>NI~Q-ArhqoIs7DN#x7 z8yxgZP0og%845o-A)-*(wS^B3s}S=zvr`pjg&)T~pb)HaB6l?rB2it&Te#2hD?guY z!Th2>-kM{LKI=%y9uM&Oi~)!W|7qSAGou$vWSY+`E7BgWH@xb}WfDlhyr<=?LTz~S zT1aHouh`Tm+fjyP$@0+ujsB#5Vno1WoZgHB1C9z<$^Lk!vb?sY`U%VXc^rH1 zdI-tK_*y^q8xtyCmyx_OmfWTp^;_k< zYiqobP@%BBVB`v~o2r9ttfW2)auNvc4fr#X@9-E84 zxg6FA>TBXcfz)FuO<#G_-ajDuVSqjCx91KkoBrPBm&8h3=5zQ1nzS6a-iNj{AvIY= z)Z@k{u70(Z$-#oLcd7RpDl)Ai&#Of82$WX(MVrZ}*P$FyF{O=`>V$VqwUpIy1(-J3rAop%zi!%E9ib6$ zh@jg*GP4|P``^+MZD^3L64eb2fmXXtQ&%<;fwh#oCP3%hXZMj#8Ig=HZ!``vkgw0i zK^ro*y7r7hJQRp!k7~LOp>lQ0dYlaC6%U6Zp}0+1U_)FAae%h_kjIt{_Ru3}`Y5bq zyK=sB;~>CYDZxp49}o_t>)jV=jA{=!C80_qCD)~q7DANTEeE6?w=WMSFmZt-6|<^m z`(2SP2DCUt5{g4O6C|Q>t3a&9a+b4x-xb!m3ji)HXW3fr=anKYkVZ*cU}1zav4cF; zRVng}!}aDr`es-9nvSu?CfMIi&`6` z#Z_%&DyNkbKzckPs%o;Rfz?4Ic017aIa*n@W)?L%j#s*RR@3&G12kvuIlwi#K?#Pf zL)DJ~%&IpHQY2W6l~zU-Z7D;*w4@aN#GfCk0W?q*B}q!c>P33x)lKzw*>HJ;)y%mI zjEXB8`S5bTEq4)NOBMRC9K)h*1WkQ*1)#19DEDc<)MLX2x)BZK)@(r-hhKGHM$)jm zHC4ouQnjOy80CtL8vMXM-wh&hqRJ80xRqq%SjMv49WtnImla4l<6E@1>)q11%Gpev zf-Xw83!+odp2?ICcnRflg^TuPaR~-*W-c-hwpjIJ(g7I*@*TA|(D5j{rhc#-x zI2zc56k*4#>zvmX_JS9uK+oJnS&hh#oH2ZG#>c1$171YC{?!Jz97u|rPmUG36$l*R zIOPy%SjR#)%L6jZCq+3;lF!P1?36j%JXv=G<3$CO5POP)Lw$8yG0$Z~kW>RP^QfKh zvW$YrMl>a65{EM`1Ca9V;}6386$G)rK#%KvqAk9D0k{Qu4=l!Dbh!J}Mz2tfA5&wd zk-b6CXG7j9#RoIDJ^&;>^c6ILhbl2hH!~OXQVrdL0>~|XPd4QrYA%hZB%&!$eS+lU zm>){sQ{rw6sB)9~H{;y;;r^W2hiRu0Cx9jA>&0BelFwa<#=I#rvRt7U8H3%Vw}cbe z9>9_)6D)7HGR`$7(-94B^qC6z0Wu@vg%(VoWqj=rie#q8)M0O0@Cf@L6DXd$dYx;WA_G8e{~gKk6V-2)eUgu|kD^yl%$ zw5)6M#><|R7joT$<=u5$Fu=|Lnq;i(@YAVf;Z0_@fb7(mo9zKZX5sbOOipJrk(52M zZC?k3+xhrLOo(QFm}W1kuPJKG8agHELq|h_W&^|=ro+W+x_elftc7gJjQ&Qp2oWsU z-c@BrAy7uz^m=&_l&DG(2h+^x>v#fadDX_wUaIu)LFc{eDd5CSh^YML=|LU#QOSI1 z*-F;MRx+m+cCnf|@x-jQ7|XP6323niPt9 ze2qxu2Pm14W?|o$E4%Q@DNn|2H1+UkNi!#(D^bpW@Fm`94#Ed3@cT783&(=!kbHnE zPOn%uqs+B6^!R!A(X)lt54$7D!YH>Y!?ZVf$yJ?Ehq!H1->qv{b^w-&nxi{}cQWs# zR(iez%PvL5_o(X)7LKtm{&BGWf%y@y87Iz*DqCqbEF`G>2?w==Zl^@`5>c|WwF1=CR&EWdlVUQ9r@z~u9QzA*T~kSju=|I!UkGBhkjT3Hony!lom?&4$AG@c4S1n8yL5;?K{u7d|pPE{Is|E<-fvx=5yg z^jaHL0QLG4*P8fX^nQSZ!H*?<)cc`-3LIMrDo6l~b>PQz{RWHYf9s5N zrZb1dhxnhF_W@86gT0TrzH)nd&>r0wZ1e+kBdgDg5I`A3FJ}*PMbwww1p5s6@a~+k z7}Fwk6?URE_DfCd{rdv6wBXS%c!6lmbTYQ{IDjSWUMgT6A*UQ^}Os*u~pAm z9QTY)gqQrz8zBpjk|lI>metVuSzr0rSM4L}`r5tdd76?Lx{Rk{dY|!*Ew8Uobsh9Z z^+i1kBu)OhngK?z&y#ZvJy^?lvA=mW{|9KEOHkdses$jGmFV@e0mEb-L?ztw6#6y< zSdCMKTN(UB>FJ!LK=#snjBpQ&pq{WI(OktJ9e&k_xN6FbbXn# zw)|{p-AcYL{fk5El}7$M94nI9C+6g@sH`L+*3L85WU6GxcQ{9DdUa_VaRIyg;}@pC zyj;86X3(-fk(cNnD58^!*AwT_udq8l6u*t`spx&!-)Yf1fPKb^2GUCUZ0W_YnK#U% zg^4*)CIzJSSA1rsT@45P>u7xZoYfi5g`|gw}bj}vqPuTSW^Q=vE##dV#gOL33$Kq-s z8ai65BF?EH>^!ZtaD}JK!3>aryLsG7)m5%cf$D>bM~oL2Bd0c%0V>1qg#r|U`=xKF zHWL}CYBZ(POfZ@EBa_^}wb_nz_`9>P;w4D!L_x-{V=BEq6q`TxpGGhI?i6Lj%dK5T zlf1Pz`-iS4l8UP?ylmT*C}d}*#>Mzid^aV|D<*Qi=(v+LR-T=^m2oPE@=;uYTd{lb z>#(0~A&KaGj7>s1snq`P=!QQc2)dzt(e)Y$PHx=FFr;iuu|i}|*qu`e3`9WY%d<2} z`q%8l07qCYg}?s?C`}p(L0I?L?AzNyy^D92aq-!qda~~ADjBa2d)vzS`PyAq_QJ-j zo&*mt;>o}5p44Ox03^b?D~=KRZm@07`@4xS&|Q>bkKgugQ3qtHF7-3#5y@xM3gyah zM9eP5=5U=7KC_PVI!)4}-%Y>$bT!gmZFesLAVCOLDke4QtAUgi?7bulAM@?&L4%1# z(dRH}CdQ;^ch~b-XUrF6fzRY^HgIkO^7sYZa+J8#F#VSKk@id(Kl*8hb6LE|I+kac zm|-nZSj8`GdzpB&X&!fv$PRZ*V8HISUbCVIw)g|$8)k9cbJWlf$&%m#wv?@h!O{>8 z0703slXd*DV7#c&AA!TTJt~LY+x*yB-wyWszqr=_;9UP3&jifjL`0KQmji0+O2J7AfRivx@bE93cc=NVYQJMPLz_DTk{8L z4^@>UDI!%n&ky!XIaE5GQ^W4o8`CO-?UYS>LL=B(?y4MUV*X1KxltLi1CW0pb}Hms z$;krzxUC%#s1&G&0UE$RX@J;J3&8GDi``m4-GDuiJ}*f+M47P$q=hLU7e?-tk|cG6 zT^!h^x%QTFt|I~{jW8ww^zw1`l!Y>+Xxkt`6VPE&oKb5)UBMKh8mg>hqn-j#jsT=OFigw@di!EDt@+bb>1qgha$c4ocK-x>?C23T^iE>PC5X@p-rA*T3 z25F?7OO^bhMmwM|0(E-dnHn&VP%wtc940P_=(03mCJM5@T)t5*vGpBYT3D?@Fsym^ zGa?O_2Q1iZ1&APLzX{)V_+E6ZnYp zCu+eL9B+RRuElMEu2LhXS$O9$`&`{m%3l1L>I1=VdcJR!@Gkoup+XE6}X0oc&oe!y`Eh4D*uJ>ONwY6cpSTPFaeSKqNs zp0P`B(!YG>MwguntT{@vpHv(9jwP>KtnJ3c)oH}N&8q!5vTW|Oy*B^5Qlb|DlI>8? zyZ%{QT~N!yF)7E*j|4frLh35}^Oo_ ziBSAqLPx@bOW8p^F=11P7af6*ywV%;xdGN*0KgrxI}$T$;xjUm$$fG(@&^cp-{6RY z0f8DG7813#oBR2}4%*S>g?uhcA^?z`_bVeDynL$BHhdEz&yxq~XmH?t$F_2GuwO_8 zwee?fPkSaW?vSwLLUn3pN6z^08xsTq7sN@~0OLFHRsnV7SeRK|i*yWrVf`Vsvjw}1 zm>KR=SZ>|T<$QcH9yPY`0v?gvk|J~$^?Qj9qS9oGdx?hL?wn3@QmC2We!c1qTm3#T z8K_tA9{Nm`4Pxf}-gxe2+OK^4a{i&(2b@<_?rJcXG}lKoR#d>E-N6^|t9$j<@d+a? zE1nW*FX5}7u%CAie~LT%jy~a)$+B=d5lVVRK$Z zF2Q(&Bxmmtr7iO=A7LS)z5)b(744tpp$pNA&)V2I4QbtJioH~0;k1NM53`vY;_Xpu zb62{NcRbP0N}}C^Uip2DkY`6RWvA)_vFQ=X*`sofUmB+}VvQI+ z@k?~%`2V2o-Q$_=|Nn8FudCyg!X=fioN^dfgm;8aLXsSYZI)6_TiY&&89A)FIw1)m zToQ8Hj2yOMScQs_(>B@6q9})LnHY`rd%E7A+xL&(?f3iV_qqLUx7Mw+UOPNruh;W& zf7}m`kFY=T`e;R_7%!ZdCRvUw82BEFSGF1N;d@NrX+eU!3LP(nOwP$~+vE_3wk`O` zzgM4e(7~nazPuN>ODBC5e~&g`|3Du#hVXvLh8;kpJSmlBVMQE#tfOUg_%JKzm>-1k zQfTC7(pf>~psieXAbUrX+Gt}Y2X#m0+L)$>apM7gqa?)5VZW$&lbyklG=kOLug@@C zDMAmluSdMV{=H?IJB2;6a*|`w@*z{qmz-tdK@S~IP99Kb!HoJ)w*L0kCGWBe1Cxle zrkoYc_AJ6cargUzplGam>L<(#Q1LIcz{&UY8DlOdg*8mW z*MwNzN#ZA;&}rxoaOolJ79IpwfB=PWX}BC3pBeuA*9o#!#jI8lC`TBJ%#Y@g@>3}; zx5gm*M+4{?mMxE@wa0<7*mi-Jr^NWC_~hEcE^SUT^nQVSm(-jG6eU2L$`PGvm7Xeh z{j3cMh+s|`dq+6a!G+22)v0U_EolvuT#^>$XC8&d+xv-`ayyZC@kmr6zb(g*&yOy* z6;$+@E&-1wXD;}}m%)o$YWruzT92GcB*+ne%ML|P7xQ|uvGj}6!|+gRqya(%JBVbq z%4jRXoJv&h^v>rkxDR-URUlHjbS|w`Athd~Hl`Xj>z%1@KszTru?-06Q%NO`D0IpQ z#(HUst?qMGdd?xb^sI>t*;%F;P#_1jGI^qX|EOkVS%Yu$Ep0piBeWP7z!auzBjbvL zS+4cFSh@?@LH3_;-OJ`NFU__jP`+5aqbu8Tq`4FJe5t77Kr*bNMV--@G?P9RvSENG zsA-?m19u>Wl*5ln4uAEdxjar~nZj_N7?=>Qh*-(8;#By-2lABjN_794`l057E&~6Nd$ELrO?#tQDBLkS$Y$qOcn?-o0IYBteh{)WDOq(edL(X~CeI*n%d2HPOA1g8r zn=hz5Uo!2VZj|Lc`@5Ex6cN76JOotCja!mYkylf6yZEBu97`mFxe!oZl=gmU{HKz` zZ_b7W6)$2LEq=M+uVd(c8k-y?#U85d5UCj1tq}PQ>50~dYn0YUZ|AmB)+6#k)76$n#rU_3 zeXPckTRGQ49kk_N_zi=&GXn2poAyy349e6tK6iOwkIFQm=RT&CX8 z%pS_im2@-Z^EDiVqLQ55ytK8 zu}#~mHFc9}-;5XfWztpK&ZTM3 zR(=#3nv7_Qyf6#-pBZt5Hr$#@0Sl};Y0d2LuXRJddR^W)&?l(4({$!eAs zyBPmoObEdcFafyH3K4Bi{VM&@H_)Mjt()(C7Qfo$ zo;eJ@`ytp>Q=+p8hFZir79A&tN(*aS_v*2R6NSdYF-i>bq{U$;oR+;2mLjDM0<-{k z+nd76n06;$tNI6s4w(=42-_vwrWSHOhuXY(ID0xP)mUh*PD~&+OIIWd7sawT<4EJ@Ma&{6oGeK!qMuN&Yo7tTlQzM`bo^<~IZbAOPTbEq|1gqt)^i0SI z{Ksbe?loIeXWI{7CLi&rSJ@+cilTDLpzjTxvhZ4G)c*>ZThn7+hDvmX^U=1~J>YM7 z)GxYkc6{h5KBZGGKxz)1Tp(HgR#p6;F0Vg%!jO^*|EhOP3j@`M)CuiUZM>H~MK@)f zRO0|Yb6Wjc(||f^CY5bOjcrqj9H6Zj;EeyNmX)mEvdegs@gv`|C1_LI6ePLa2DewlB@k&H40ndI3sat@beW77*mE6?32AHCOoTLsk z_6u|Em8{Yi%Y&b-O$Ug>8OYBwv#2`9fePAX)hm5SJ7D*ZLxzv_z0&eP-JjEpg5OXF zcA`~>5fW7E0S?Ph9ZQT4;3)oGDMvTwk+d5cE~t3k8MsnXvySmd$e}fLQ~&y^$p;QS zR~Y=OIo|SLNLbo?yfY5qjYFkD9>vNJRy%8ag4kG7!xCN^8+m8_f3be~u3 z!SxasO>Yknk&<>C@e{AuJOeuI3 zXEyBg2jb3>n|kCI#RhM0ubip(NShhm+6d%~Xb$9fP(4~@4yKBqO7C2=>E^CprtR&O zWABI&!td{?%Vs#OXnJJ-oo4z{`UJnRx@Bk~+UM95sZ(fXJTquND*SaAm5B=tF>*GD z?W*8=Qm(i-hkdzX6=EFNG#ATCf(82Jg2)%#DBr8%34HNlvm5aZq${TzZTsa>9i)^Ks^8YC8?YG)beZhvYqA9 z66v34@r-M0!T27#Hb_us3?v)~tPk=hObmHkv93}Wi#;tdKJzx04IQ|}S zgknJ;jBNDVzL+>>Em=&1!KSzy=*}gsp>tL%+^Y_9ilRqQ^=C@kAc1u(o6fwz7>Dgb zlU9V;SrdGu+C4nR+Dm>6r?|cFQ^~YbXn0aM;;k?!>lx8{{GF-nf+HXCwMi#MpIzVw zy8To-SA0exk#p{pR)9J`--Rv4=Iyk!H`;0O6_nF{qkb|11g>DaTyYOdB(N|2+89WK zI)QR}$7&5};`t2-lO`PX`sWV?eyFLnX{uV`DyE5FA)XaG1P1hb3XbXdPof1-(H@3a z5}xJ@Mv`UZ#{nLsPs3kC6nHzGZ%zaf@~2n{3udL z9Otj5@2KxcZqhIJ?ZM#!C1u@U5sQ46JHZq_6NzUB3v&jFj88&^RzVIhh4 zuEZf;H>gEMR;JaoYl|Ad_qVzC$@|u}kxedVU!BRoY_84{GJll9`W3#K*vhEdqC=6beSe0*YMA9?i?4d^a)y>t;yDA3-3<*ZC!ZT)$9vYa)I}$Ss z$!jd>scY%c2NlH@>=L;;_tkiOiKKHEJj{h{%iAz@* zFxpS0uZYaY?vL>sdw#`fM5Q|ecb*L^jL(6}w1_b{89L}yi)nIIX{P8)O?~d?gu;NU zfUT=qHS=X9n`89a_H6diP2D^9y5i~eLd7&ruta`a7j5*M{gK9oj8lh99(Q$D6Nt^c z+WsFZy$kBb2L>x=s^a@Xtr79l5n(kni44VU_+*%;$|-u>ULznJ2`hPHNEcJ1sSoqP z0EZf#r=?~ym~J^IWMD!e6QKHM*;(}co0z-!E6oR!zT_dURCP;RxN_mQJsyjv>BnlU zr(IRe$7g1rdn|REWG0gDfOw*8qJTu??Zg~)JMuSAARYsAB#FQ(SXu7s&@?*;5jYwCaOHm4_tc7tAegG_W%*ao!X z6{vd`m=QN+FLR;Zi>T)Iwxm7BC$|{+S#~l(JX5EA(9!60`nbZR`M8Q$J4%x2xm4(yyV?Vw__%19 zx!xg~Gw(?trWVS_7>ch75o!`#C1%m~g2-5YOTe@BE%nZ~p*zLWL5vHk`l6LqY^CiS zru1Y<`*R(YjDd+jc&z1b7T-0pVRlL5OC)1Aorn4RWIVUd3c12H&l}4tiVj?u6+goL zO&IY~7&Pk*eXey_Uvy_F7h^Fp<|xYEYxKgdQ`p8Jy?j4#b#CA7tEDWU0z~dlkARE; zpcWmEp)5m_K!>X1uh)MHW5gl~lD1I$pG>W0@35+GVmYJin)1Z2#`N=2hdC{pMEs)E zOe4wp#+k*8_+W6WIaze-4sX2aolL8WMWZa{I;T6|5g%ZIgbc_jnZvF;Dm_y$_Aty# zKZ9ln^|>OqX>_g*fMP0yBk(Ds!S{7H$2Z?k?Ac`riimhoc}H+6(5eg%(j_*e5&Fs&0C-t&=6pUM?IdGOe)$Zm0{qcL>=no9<<2uM<;t>*LMP z`5R*q8ykxAZ6OTf3S@3TmtPxGLd28jgGOa3M^X~@?;cn_QRMq;Mb$xX{<0f=761+E z;;a3|d;6ccyc>-Vs6wwiRoJ35H!KI?!nL|XpEb@jS0~dAi-^iqf|0t|<0}L6L4^Li ziCAiPl-k=Iy|$EXyy>T!&CUX=(Ri4eM2ooE2-*Tz-J-I!cvPHsGARHB>cUyJvuiTR z*$6bq&rsY~WzxVX_y5!5$wu-p->`ITMc?tgg7%hvj$77W6v|nfW<&L?oUacaJU^UC z?)aU&3ty&A_POaEtUyu5#pHhDPi{;2tE(Vji)Oc1q+896gTa$6NM9dW-{-!+^hxXr zs!7&)zO?TzgPMUzwn&p|$pS$GTkGB+sh2aeX*Uk==buXzR0|#<%l>5*Et!hBT;jB! zTlmoCh^)XPGaBg-qt3hm(fgfur1XJ|nmqX>SxJiah`HfDHW>f}% zgL;TMDza>0<gy_w6qew%fAdsaVhxs-ZideT;Oe-0*WG#O9cFhYjXr4Y#@Pp z9#9axCb%#UuqMCK((*xA6OI9>lZEMX@$*+7l!$(Kls((%_OFf88Us<%<$-d1)hXcD z3=rNbve<=z*acB{D`A#G7$}z}H#%O)-kFvU-i%Ur-DBYBoC2R=m4)yqTT|x&LYvmQ z)$;P})&7fA(lOQ;jo>wmkWRorAgM~0I4&R{0Jo8Z(Xst6?{et5$Qj_FY(Tb5rJ}&3 z*IReW)hG_`Ch$jqf|zuyTcIjJfKCjMBaZBt0l#Lzg?ud;C|kpFcC0hI;KSQR1>}h3 zh2tx1f#Umnf?MOQc3{+Oc|2dXW_c{RZXU`0p_IbH!7bR2lik-x05avUd_bf4EN6Wl z>c(;!I^pw+3{mCILdR@aMs~cHLPg;FK1HW3{MvS*m_F;pOrQoYGs-^xioNsrTG9j* zRUCwccNmZ5?e~<=*2Z$OWH*L5Egj{EcHBZp?5wOffmT*|uhrs{_KYN8s5GPx5bnksMhvIyYN@zONOqlrGVe!5c%Ulrz@3zf@th(l*^edb!Sf zZ)OVlGI;5?WmBX}%MV%v3_gl4W83! zm$M3nkq8Q@ZUkP{qbX|%kh6Rz3e1bS&CzAI`mAZ=QM-b=S42#(MJARG4GH;QtHJ}q z?oV}&Tok3H$TR>$Pomj{G&#`X7^$$IN>R)|K?9jxbo5|F%BgSp33@GPYcvB)-C-Vi zz^Wcx%mp$YiP!jdtBd(#zZW_!C%{^wj1@k`AkxrSM4>N|Qx=JPG1sb_+g>2C0rWIT z1x4|my9AWE!ktlZ5d0>#`|Fs5%K=E5afh;{oI%&}jtHtX4Ye8jWZyvVFO1+AYo5yU zLXzb}BIb~{UpBYC+1Z!0 zPN6Tvnz5`T&MeLB77&9eXP_Ss#BPZ$VuXxM9&Cis%%7LnhFb~(P@-kMxUyyIS^t*O z(xz_*XQZWZB$k3@ELq&~ZP0DZb^S0(jh^!~fv_VtEFmI?(Am|oA`#aT>*_?mr#z9S z{1)Zv^DVCDM?me+NGyxyCVdAYJTAFZAm3Jt>GsP8eX$JmFk;NUjdu+0_uzXFXQmZ{ z$nYC!RSbe<@>LXkd%EqiPWtIHY)mB1@%d7KE1;IHavRsYjKW=HEBbH?)-+GyoS7+k zAG7shRq3$iuG57RacN?xpT)&;25`z(?M3c)-7>xNL>b@e#4gO$ObCV6?AIC|9e?_V z-v^U%zXqw9EjZ`7si=dYVb+ezyTXHl%U4Q|sAH-cVn5>+yj3O|aj(Hr+P(2OEm1AM z97SoklC_#n1okJ0Zu1xltng$<^!nOAu%R%%!6Yyt()mwUn-&8PN`R2O!3YrJv9>AK# zdDpx84B{tzKqN?tUW$2A_=bD;A(Vj3p^P-C?o|w<1vJVTpi`IQJNOO8TPzttcoB~p zN%H(76c7>sQzSpNCWpn-_dJ_>#a{iefH)IWYv{%TD!h+*FPw-6UWR*b_QdjLUYrQn z_Oy81Q2Rk=DnL$a`Bdfzr8|6dSyejhJ2ZSYYYvlP?1h{n4z0@IxZ9s`30avx0@#1C z;*`Z+3EaJ_vLXib;AZkzl8bYj#f6@g{32gO<4hhh=hs0(7X#Sx2nq!CyUgNm*JecK zaH_qbVU^sEFj1vHtFv&Ed=bvK#}JRU>@`fF*RD>j{ zlzgE!#CY8WW9mLGfy}bZ;^hNa)Sfqa3#{i&t}kMHw${ER32iyJd`wtQd`f^Wb%B*V z-ZYmLcEadf1wb%r0=}n7mGYE$EM`eHrj_3P^hjVNQDV8gkrrz**1gBZBHF)+CJ)Fp zGg32}>RMf40{&c_Fgi1WX1mKOHPOX%M8JXNss3WOnDa4S2hoGpcH4q3dpgS1^9lg! zA~bH+``OU)h5BAaPiRaL0@n6Z$&wGLYysreU`CYmlOIPHr|fD&|4=}X8&r_G=PX1F zV&da3>cRhc`*;GsCHhEAB#rq{yMH{cyupG2IGz!BX=vy|$E61poobAE`24iuW2xWKVd0`1l5DH-u6mM~wI$8aw%pPaxKMLDVTFBndTZg_Icb^e}#3TY$Q4fI_5nfzGiVGHA3L!tR<_A||8V)zjS_ z=C0Z|8jh&bTGwk!g*z%b}x0>RZhpfg-*)^-@&YQS)toj4Ld7{K$F!oagBe zpX!z%yfG7MrjIr*kJ&H>Wl@ZV+KnD?!2X&-CTrR5dLv}`3se71_x8!u**Oef%BjcdTxxJ(5EF75Q+9_~>~b|O zxTJOK15IL}H(a!mQF$>KMo=O=tH^KkYr9_hN;4$~jI`GLt#~B+uYiF-yd0aSg>_0_ zWD0N#Nt30xUj0Xus$r6GCu zo0*DyOZmxLDf|t%ti;TthA#nv(&U|N{j}-s*ucEn-PU$h$8rcwM7CPtMDzd|bO>57 z^$uc)-Mu1&llSJL;y90X8D$uBKvDK6`^;C}kmEI;FDIUF_#YqWYBTPDuCusTVKAsPvh6HG_6YU5|0yF%p!%P&f+mipL5A zD3R19R8wXP=j@3qX4om04C2fTRWrjC9EbGQJ=**-ru#f?;&Haup^DhvUT(@zbGa~R z358WX%o};q%Vi+g5FC$Wwng3a)P*DFHQbWIw4TJ+Hfi>@ZHJ2%D601`C;K?V_8T8& z)2F?)?-mA6pZDJ^59Yg@4(Q)_1IG$DT6jQ{oMfHjcf$YxIsO~whX)Mh1qTepJsdX+ zJB6&1WZwAWIo|^yi^$$}z`gN5Pyv+x00Jn5RgOQ$X6R^n-rQ%2vAP3-OtLT#8?PIC z$Rell6$32$0t}g%?Orng4L)!Ph?Q2u*7oGNpp;Pk15>)wp6kjVyJMfN!$Vd%47>3X zAfYN*;hjCSW>3*-WG!G7Kq8AamUnhFHD%S8?Dsk?|HLW%$boXUvbh&feN7$O?q)HN z5qz`wl4d$PLY?zB|rNhwVW(hx1vG(8qi-iyO z#$M{d$mh^<10{V+55HzJyb_3vwMdKvbV$&3xISBT_nXP{0vGJ#-^_E8huyIyV!870R zGUr(}QV7grf6wwp{n@GSZXAEUTunBkgdje=D&ZY*-^UmX$0$VhAK2LzSR90dV?FM6F9iaDIVo`u5Z)|yd*K^3c+I8-jWdNbmx zt%tQe$dSxNd-`3=oLcXkOORVza00AhSu0Z}fhc&ui!}9*uC^n7&08r_eNaf!R;H@A zh6JrwW?7pRVqp-h1xrm1Osyb>?A6^j;<1pA56749=T6KKxuBMgSp=oi&>0Jxe@N10 zib0$(OD+_UC$7p%l2aa3ecFlaIoR`=*^;-{^qM)ZPN*B!c-TgHhS9^R+2{>VjFPoNOOx?K5iu6Qh*0SZRTClRGZIW zb!~m$mwMV$ODL4b$Qrj3#R^+pITh!4iSH)&s;yNKP!-<)I%5UjRwlB?47=>hW}5D( z$G;^|0gM@Pz-0i_DDyX;mY_%3mbx5hhD8k}=ulW;=6K4+ul^y5o^TCBP3+VR-xfC- zxY~dpfW0MDSUW`n3rhumf7}BGsF8NCq=Py|Q{JkzJ;#3hed05pWN0~SB15d?%rxy9 zbB?oowQU2Zd@isar#qf5I}bu@1%MKU(~Hg73A>L4eEY`g-`gc7sS8pxkZu zhJ4y_&q}um3(foH@ctl*kcj?jJ!5{~efD4yrg{7U-~kMY zYO*Ylv`TT=xGx^fW*=FB#wIiNIBAA;GUBJfiJ@|tx0rjHT}NkM$>Ftn{Zz_IwwScT zo2;1I0|PG&6rGI-gveAQn4;NH!>qp-w&d8eu1apiG`rAn+HF=fE4qmKa&~{dZq<6b z7~GFu%Ch4$6lc3@Xz_1*8vEEEq_}e5XmW@l=_~~_um$iz-kYLP0sMWB2j_~ShXIw_ z2y^-i>GIVo7Eg|j5SX~uX09mSi&-t)i6Q5teim8f%5C4czv-@C{G0Yuc zoJ^~dGuvJ3zcG{Jf0=SIfVD=;ka_-d&+wFny>XN3;So00Cvsck4}6%Z?c#{QR44OfMO)p^Qy!F;6z^GBY-?5chL3^7}_=Tm_pUX z(lcvf?z{Z1y+HAaI75YNCiDw~F(s~-=rjG5i>1ThXmR;DwYVJn{Rt(@{`A2nhoI7_ z$b{#v2d{;|O{^e5yqe?}W_3#`wplow^&~H& zQ8ag{KCX(fNTYW$zwIe7^ZluG&1`CJ#5F1&nuiF-g4+oR*JT~{xCuHsu*FD~mtCKy zz#Tk|B@iRaDJ=!X{AY}`02g6nLT+TwLI%192^YUd6Kl7iW%fRF-?oZenwY;L;&h_- zWQ@;u$#%7++AT}H0zE;vcHu>P-3y3&@^i{gdPA2C>0!%4SvS7XH@EI>ea(ZqGE&Dv zrk59PQI+?(LUi>mKF6nNF_lmQ*r!0}D&rx_s7vNgB_g&b3vVqixMJzv#LSsJwe@@# zlQ4dXvp3x-jux$@ufJ4`$5NINWG$C81jWl8naBLTXDYMpSj{;54F zC6W^2{TK~st1-?WFJP>cI-DE`GpEUM4|!2q?}xzFw1{3i6%sg5nyS4ts@TUgcWM3@ zE;~cZQW>vRKl8<;fhZ^!U2&#VzgmZ}=dbYmb_}ckaUyi%#Ev;L3odQ}#rel%M{d^8 z9F5~8NMzrazeZGq4!=m#!}A%DKm|#5*h|4LpC!w{+qxdC=)vTheewGwaOf)SdW`c% z3TG0NGWYKGbzS#yXP9Jq_c2oneJJ&j`RaiQCnPH7QqWn}lUANqF}x0sU1 zX3*aPs_uJSv)|%{5`O`)UgOJ48O&j#H*pb z5GfaF0Ug53-GcBnz39vWifT+;S0$^O$$&<1GfkNxE+E~bSRkd#Ih$_J|7uJT8)1=L zL?qOunOlketvRo8WC{2PNKM;TBoenj+D5)L{XKIwt?}9!pov1=ORxz30WC`mZ-gQI zf&Ksbi);8vOa%R)U5+7zvWrN-!#S14^IP()O!Rk-5^b(toDv#T@}Bxd6{QW*oCuJH z%@4exWYr5gcLcL+CxYHrbVTneJd+UNEj!;$^#etSz^9t`R-L?o51r1R~vr@zlVghyBCin|xjUhTFaB9}~m2`QEpF#fayntD$sQan( zV8Ffrl_?x*IphOJR{vBY)kEc7AX{qzEnOI!a#FvPKK`~#DDl4hO*W=m{7ur9gQXV_ z$K|_K$Mx14k7I;}hQ!+AnzdWN=!{H74^jQVV&BK#&BOkna|#0Q{^08VRPvl&b_PA* z?u+@y$9!P=QygzRNXR@GCxlmP#8RQ~=U)5^FdTjr8j&~${>|C}h3wk@?IRb6gZ{^p z@GmRi9{FrT1*?6c!m)?3u^@K>UVk&|2p(FbQhZPhuk7Pirz+bAq)d^d$FpG@7q+BvKC_ zvXZ~8{oL;Dw;o5xKN6F> z7*o0z4PJKS2zlf>J9AX`KF=JhKGSnUTBLplxTyp5^TVnqf7@gh29VPn+>YQ2fXWP0 zPICvA_{rROs_`nj0;rEOEDunW050T)A+XDr(*`1AF06xw@NLSc>Hr|OQh=ZEPB_)&+iyXv;e^<7koNFb|fbxmPzsXjh*C7%kX-(2_rZIyz?Ra_{VG3 zK`eu)KKyPo0LT9P&9vXMqE7IX{W3t8mmX45v&>fN)b9e!)7hF|LiQ8~l$iFe(`Wy? zV4iES&x?YnRyTmMZ8gYx>dfTvoqevrD-I|rr9<+%DU8x?MhK9%fpcUN#ECw6fj!-S zV;lH@hlWJ%>yaQsYGBpGUu=nSq2(Um>E;UjCpQlA&liJVUF#zIXnFR3u3|C`KpssU z0$A(6FAQD_yaCgE`}Ge1j9TTlHf#XcFprLR+y-1LN4=gy`Ny~HVb4-5%*(-t75(V9 zgd>IUE9M)L2MkR5cuJM{uI-ELs~H`g>quw`3eiJ z`(Ee2#wtk3)Du3OvM|oZ+YE2aX_h;kbwRWF_|{Z=uK@D7*W`Dcs~K09Pz-2-!T$Nv znyFdJ$f>;=7@-x=C0;K~@9Go7VOInEGE^ej6nxCKsgnG^dO?x7*UxyoeE!h;XTqQ~ z&p>`dCUhF){yfZCbCElRbQZ0(H2f`2NWhq1MR!xKK zvol)ep;T(xl%dS!>rD%TcO(sh40W7MZA{cS^!%`6GO%lVi#gnuVTx8q10U$Yx1)F1 zKO7UD$p4b2kNE5(xX#gFmHO3Y|5O70XM7e$xA~)e-gULcrw6p~{>&KM2r1ISEW{FG z!n4K8dz~5RDp2`u+c@?5<2Cj^?nVsxAbl9LrRpk{Ephn2y479Wl^#rW^8XUH!e85d z_5D(L%>HtPVaP=5%=xN08~XcF#X34*-Cv^VRPOV8r*CaLY0uuT3Qe3vgo_lPuyRf| zuJBda$@FIWLc}N{24UBum=aeazf%PM7o1MrnWx*P z9@HdP*hxs@*d3G;qj?se&NXXd21=7+?CICVfF3gcVj)vA_2a)<<4U#0#DoYxXQQ9h z*UBTj*B(8X7{Q}#T(%-IR>lkDjap`XEqfMoqMMGEwc~KX?!%I(Qe5*Kafd7(&TjOn z(#aG%hX>JgvPH#l`QjQZ5_J7hQbx>u5hl%eXLe+*0Zp=~a@{2HnA3(gDS-Ob%lTTy z70Dv2wv`{7mA3{#F5Gqv37yAhnrqB3{)XufoIO}m?BdV5Yl8)C(`2V&c?)8cU!}F zNk$MtBm;<;Ep531hu72{_os}H*$0i*k1=DMF>WRq1ZRI?qn8)2i^Z4#2y{&VDU-Rg z;2yL-a|=4;V}_-91tVXvZVrQ6+1$j%C3ro0`3<=kreW#Q#R`&^g9#f=)Lgv;BXj*~ zRc@s3(ykKlu@Dl7gJlymr373Xdr($wT%1ia^=_83fzhnR7uN*@VFXSdGueZN1gQ^f zqm@6`rZoPNQP7ZrCT?bqR2}$+Tlj3+j@vimw63NR@_y1kV3lXN+l+Irrws^aWKU0B zMASx;=o)j&&eZHx;0qF7rv}ILM*pOWJYM}+$jr)WynHJn{~GIM2bC=_+KJcu5=Hy^ghz=eBbC*NSbvN&R9rRHULY> z9nDt0>!v37n`|Qfxv!}xfJU@1Tlsty*9_F=P!qRZpi8}}z^A!s;m4i4m5+QmV-juz z{16a(&0Cj3jNj((PwO%MT6{|)(wEY^DD(;VKs~*V3(4`TeN~RU_F>S`s@jC-y~qfNN= zs0w0hJ+y}!O*6v+Ks#K~?P@q<67jk6n3--0Hnqv4eO#RJJWcZn69gz6HUBO>ce7AR zU#{SMwZh%6y3%yT=IuWTTa2vJ!%qW0PF3mR`7iJWm}pGRWwYdJLJP5Zg_nOnNV`w$ zbX6m=ogQ|*m!8_OkL#r2F^*(jZ~UpG8nqri94)`q{4mr1Vt!e`>|-tC(Aw z>QH49pi4;RP+6$4sc9YJKSo{NhqfG%)5P+k3G$D}X})J)?X6_*dY zNwjeuX!NhCxIdaUHhVK4!<+@pisj8ooBrg(ifgMgJtH+uSc>jT6=B2H&S~AUmiY+Y ze1+!FMc=UH2e#5>YA0eiI&9@1=DYl8@XAw~JIi(0p|9_}j%9)^hkEATvksCAej!@( z>Y+*?_hKnH0o10fKCOFvC1O((HNxr~|FSpj!B3@Nat%$GWq9_0mE0x8rD1)MIm37; zqs7ZFv&NRAlKs>a`B5Mh%UQ??f$a~@x#}9BWQl7(@^&Q?{>9kn`+w#m>mQ|j&tr|h z5ypVvGvNC;7pgBnWdA{B+^46?;O25B#KQSjQ;PX$CN#I8HGQ42aPoTv~{> z!TLo0VAwK8S$`*@J5(F8M|UVN(lgMnky_cJ*--6MS}$F2l4T=`E!v+7uZ4kW6-($d zF2QdN+7D`f^#~IqsXBYR=c}?Tc1BiXm=IL(^nw@BytQo>gG#!PEs{_iQznMHsi?L` zZ$C5MY(1B6T_p?tx{;9Z1c^8is?=JD5q#xnW5zpn%6qiW@|i_byZ?N0xwD)>O+x?`* z5SSZt$SJ}iOICwdDgCaiS%e0*sh!tJmZ9#vnXir-U)Sx;r}vlE)^BbC-=BDyEFIX18tXv; zK_}O*ktHLWj)XwQhYko8(!tY%znb6b_`?Zi8vrukDj-hJhrWElb<;8W>(74~&2M*A zjy*c7y{GDK)kW@@CR1$$mcE#pwV26-+HPNl_uHCAS!^RZjwCTV>Tmfmw~}QU_IgPD)9yS#JX_5iLicp+ zPBJ>r$aLg~QEi`X*`i|uCl7o=<*uq)jX0*~TNe!E@={T@G$`I! z>QOm$myEpT3cPtoC-nrpl3(3^`UX=2TW;_>`v?2~Ws2a1b5tAiEWDCi+B0khHh3ZD zCdlR5a2<^=rJ9rO8@{8u+fz2etF(#cp2y#(S=}iRz+JYT?&S>Us)qp%h-i*-+U6ZR zHLy0_!L1G-T~wB1Rq4MuCL|X%aE7yANcq!HR8qsqH<@;;>D>^wDpf;)2>NFm4F(nl zX#Fz_;7@&kw^{vJ%?{&q7WtwdH>bCMVr`|6qRXou@9pdBTE7|C2FU$+O)3n4tK9euLx?WV7)bWG@O&K01wf9Er~cKaQLktk%nnb(U!Z~^qMe^DE*+ur3R=pouB8Urg1 zh&S-rN!>jGxS3+5-TzvQbO6*=DiQziD6a#j*1lCepTP~lAU*>5V|XP4iX++OJja0j z=Y~>){(+1#qp*I7?76_{!us6u+;V*a^v2^(0KY&KM1a<6Uah`m=(*C!$>ZxhLcqYn z|mpNZK#V7+jg^P<)`%3EKA6u&hX7HY!>-(OJ`MJOc^d{v1Tj zh)d_BUaQ*e$e_hdkT0q?IwLIG5)8VMWLXnu0JS0>{Lg^HmCMK694q@vJg$pyi`#|G zXR;y|rYDg6y3Ny6mF$*zb8-6YzLN4^(Q1k6%9EAQcvt;+FTc5E^Q>(R1Dw+oM&}vm zoUJ#KDS~c^yKpLe?eBcT2w%ZL=Ke=+_XHUUk`bXxnN?$3a<46U|`N9+9YJ zOgPQO^5fw)ef#G|BOB;-h`7TC8yoKsM48Bk%o%bl1ypi_(30ua_C7uj`Rd@Xp&7<6 z?-?H0ewBd$g+YGXWc{hMcA)sFW7;fS$20I+bPSP!j8FQcfBBnmp|9>R%258i;U*pH z1%gs}m3Q1uzi(f;KGu4Xo1vE+kZp-rDe1w^`+;H2%o*;!w>SM$T0K}nb{ST_SSNp% zK1Xn8FI1?K=)B_AsFIO|Etv^@DmfAt)Z!In4W6r9EVn2sT7Vt z6?+c+lkqCw4n1;+J>w-X-)AjK&@kYQoDuB;Wf2}+)Zc_)T=cH?aGUPDKIHVS*vg+u zV)`(cPS<>E?v)JQ*Z6HXvkz&%NrDjz)S)tB9n*4obA!NnbbCSxA5l_WHWKn)UI242}Ts$Y}r1^quy?8gY$)x zk&}u-A6hh1Y%u}vI3?N>zSq1m-?l*mP-u)-DPsDnBg6aVsIx`X{3bfL7rQe2Wg>w& zg3Cr*I(&PY|Ha1@N3eLL8^~XfG$`H!(cV~jEWUKAajyv`^itWoRmA6}WeUpNW?3XV z)_TX7b@RqI1I~>x_wBo0oaH}#6FFBXSQ(FFa7dh1-GZpkyo({+$nJ@*{^f5NfV=$` zMbTL|@gnb2Esxq`RLjxy@Z%JQ<|-vgo;?<`k2#MqPa^CJ_M80KZz$@<5T_mixlGqtZZB4WkxIV~={;$|-i}KB8 z{!Mz2f&HZ{)oUzyTkhwrtQ9WM>wT))M|^FOl{qj}WN*6E;+?~646N9v6KfY*(1Qz1 zYm8nRSCOn1k1BS6+L(7 zRDches_6Eh54g{{H}Btj%Q-ihe>pENH9k=2J*<@5ElE>AAR_3x+-jmUQ0|8E@Po_2HbF_CJOqncy#s^ zV}HcmkpcRw#gwGUek{a1>Clln$b#LNVip)RmZ4u{IWO<|+!_%)ce?CCVi0F}J)+$~ z%g5PiBNOjUAeFZ7pLz>;?}c*n0F)}26mEZ14#0p3mg~iLsx+f2WRV%`qM6N0u-p|= zsrkoLE+X4+Tp%TGpQtE4*njZultQ|6`$^(@BrqOC7SPl2UEh39Yt!)o0e-0q;B@lR zZnFNECXDrIF7-oeZm=6o2EOL?zABJ@e(8EUNN~ zu~V_!R87-v*34q6czc23Y2Oza4u~7zyfilLmCPGsPmYQ_N-2!ecCFJ}-dJngo|~|% z`|oxBbU~TIxj1Y4Nc2+dTU;|t)$)u~u_a_5q9afMa@bDgRqYLt<}U;vN^*TDcG)jA zG1asrzN1LV-bc4T#hL%|=_J|OLeM4mCdde0-HAQe^fyfOwb}> z&BbvkM-yI5Ygjkyd1o57eVF3I=!RG?(jYwgo?F~Q|G-biDzskHSX zp5-E9?)E=DH6DF#DA4aCQK3`*=h36u4b@r3a__}R+IZQuiO2@fQ&1WmZjCQJfm>{_xQ=%C(M;36>i3to3sObByp%L%T>O$?}Ylc_2gwc z3sq_zVj4d%cs0L%DVx(W9~5;fkxJsm9}d#WN{a-T~t9{RND%W$`7 z4yqCTV9*pq5X4AgIrK6^N_YJM>`t&^Up}{GVP{L;q)0Ge;zWgG>hm+ycjiB5&HPA zb73h>3{n%p31^adh8>8@j`6_#UN>_A>q1`S>S*HPU;R|lpn$_Uzkd1$8>>7v&qb(X zOTg4!rfIAYpVKnwwRLw&w(G3-sDSc$fo>t0usXQR&uEdz&41{~w=BozzsYfVd&@kV zhjey!wd$XM5svj@<@uJgdSGPCChlV}*ZjoQTrg7WZ@e|3|JD}kazY%6HWfMQamh$r zERb9vd(bbyEVI9t8f9$Qy(R?yoRp+DeP=cyq5*XE%shLr> z&Rw&?9qJrS5(LVOK%IR2|7nhzc_Rn58%tKU;E*VuHxliEH|Oohb3X9@gDkK;HuE7x zCDFvQgtcS;&jNm2)I^PbTc36!T>N8DV+lBOR-e(7*n<;H$>sr{~TKSf3f!N zQAwx&ySE*uvU91EW=8b;4@Q@S|PKWHdQrWEkHT9G*jQL)x_@PF$4bc=6E$SiOq$# z2(5Z(nx&ii5ZgX>T?KiN5X$)DigC^ybHev8yF{7wE84ZJA|NeVfq#HH#ul{<4;2 z3Pu~`ErOU5-lht>G{{pyru5jc4Wy;fU`sh>7b<5SIpxI-s((S2|pfoquL}`07JJ#x7zaTK_ zF)Yo&a{|8Eon6vV-r6 zva~D=Jy!5c>ybL?Gur7$`Q1=V85e2AafR|z)Mj_t9li5KwU!we6Yld1~ifiyq~7GCSGR>!%Y==-tJUlfH4HOTuM6vvKE;cD<0Bj2tEv@O|&GJn+g{W76B?WmMMSM9vH}Dk}UD1vFb0 z+Rv$vw)>Um&yI68cXO3>(7!Rv{?KZ_{+{4gng6BO-f(MjiczEhJWLdGQuje;V~@%k zh#`eYU5rmHj4_$KP*1oH#f{dgi_XzHIS8<*YA1bFz5V@1;O`N+qb?guLqbCXIm=dJ@M|iV z*o@e!%K_b{Rr@OXDZ+*898@Q`B*qDV6%9`DZGBW1O<*0`(;^{h*mgHPz~b!0+4c{j zZB}V>YIPl!*YyX?QW`A-hon?gS9;oH!!pipCWRD;{UT;xVD{WTfVn02mFmK`&Lwn>akcLrIC|F{|z4(h|eoE#sxN3ihsL6d! ziBn$qi$2l&h;Q~`MnaY^20}Yf!Q=FeO&MKVE8DcmxSI2?CLq#eAkN#G+Ru)0PDEZ7 zeH6~>IY_^ACSl&79$gL&+wHa!ixG*|75*HTiU^-KF~!$iUs-?#5l%7`Y)h`InAeWK zou8~Sv}m$Zc+L@>f>HjDQbY4KCyoNJf8bo|e0fX4m-eP(Mi$oDw(%!`7lmvjDt-5H z$C*#zllzOTn*3L1_C+dYN?BD8Pg#dXnLEl`SdFu60^ep$_L4z9&>?8GrFl>1%x96yvRqs^2|n(|iE5Sd8g1&mpNsbO<4E^k8y0 zOg&M}YF^tS{$l!vI@&61-uLga_u{f7JCtA3{#r>LM-MdhiWq8Yss-+($rmSs$aHeA zFZ*N06*xKRBIx$#VO1YP_h8zMCg#7_HJf? z__j7Lsj0NB6p_uu8|CQaYkSuQdYPQa`?V1y}*gpj`Ef#NA<-uM%MjQ52>JM*N$f2-MClDA$1VvTd-m_E=khyKxV3wlpG@cLEIV2O zAV3ZFLg}XLr8lh*+DI*|7=cKh-5isGBgewM5-U!-lA*7f&96)IQ|?C;xG5(X+z9F& zX~oep#7X>Rq@b;PvVDUs6-@Qpn7Mikq6MP+&_qV`EQh>fH3(c}=wk;Aa7&JlJ#c~6 zMrOB3W18niLKC9n+*Zv~lp%qZP_=tUd*@qm`6;P2E3sGo8ng~SrK~|eQuicQ$h}A7 zw=N}d)b%(D;aSbM{g&mMQWEwxf;T+0hSi$Np+BXRyO9D@?qhu{m4nDg=(+ViUxC1A zpnEZf3k!5@x+$X<>)mwcP2Ztu%go@ZrO4qtuS><=jlt2wUh$Yy*6NQg%>t_?Uq(R^ zA6fCd|0v?!poIFXO{#<(>?&~kR_WhGn73&}D-63+8OO6-CV#GiNkh2HDBAqyT(u?b zc1#;A1&8{CKXB!KhFok(g~~b!69x1Ay6+R-w`vJMPmb}ji(&9rr%;Yl){Xhp$B@w+ zQvr__OSmBHE*c*_d~}~&2!IX7FP3*dTcQ;8(&5FL^D19cF)+^|vq)nzp<-grilsGY z*q`cQK0dZ{>7iyX?8-l5EQVPwaJ@LBXZF1P?gBzhpaC zK(nz?un+y#^aE8lEU2GcCK_2Kcq(rHlOK?q>!6k#SedN(!Z&qM0!49Tr2cT^H1z&KPI zb3C@3MM3J5OUJH0$aBtyQ9n87&Ny~V=QH zV;>Z}e95TY;rjA^&5^rh8g{~KJZFS)6$w_*_u#NGk#d><22$?L>r{cndFr{*HX?#i2yA!k=z-PaxL-`!C={N9$SM_m8QSk77M7?&>0s{BzY4&TAFiZb!g@Q$ktlPpg+b-}NB_ zVQVz8uzjnMHK-)TDD*4HgE0^LC_2ZEK)_U61vbZhlo1vc^@}f?1G|Z?Yt@Zo{G5+< zLZCohSZ(p(q`-0+Ys8H(cZrrbe5>uCqWN*PDZ$ib^IouR%yXUkkJ5np!fdD4f}9n~ z@p2El!TO}TyR5Y36K%osY!8APz;3{8tOr$9{s`3O`rIxb=isnwA+I6Dp90e7m_P4 z0t8qipJ}ywAD4{6J1GRTwASoAqwMjK_V3(CAt)KHQ_sIK#J%hmEh|!+bjIXYE2gYu zPQBnohDpqRyOt}Ejt7k)*#nab2BW=I`HfM7s6xi{dAktE50V#;2+1~)5&^o9CNs2e zR=)iF=`}ZCOG6_X~12EkimvM zFgbZpxd(+Y&>(BD_^3nlRHR;~Yny%@t?QS_*)((a$=7$UhngK4&V->XAc&f>EO)nz zs20J2ygsNjA7vgc2=^4lImdDr5=r|9-mzwO|0%XGH*5r;DieRn(^&YS_Sj9gcEW;n z(An5y4WM~4K@)mpJX7d5o7XGjAY{NW6AvwkI)u-g4>;;_E;5alA*0kb4a8;?sd*tX zPUo2u2=Ook4x7>loQvH4tQr;7#?1-4H7X0$j>Jt~0Bawbq%Iv`t+39lXqj3Mq$-deOKt zW^-6?ojcf&Rh^W5U<7w0z@#no>wPnTGv@(*#2uFN!&5FBF)CFLkB8p-C}@!r4-~L5 zW8Bs}0dl6IzS#e^;(SfkzbEY2cXmxW#Af; zkt%akJ{^BNx?)*`7Mf{Y!W1*V;xzqf4}$B3G!e=1P-|F?8x1xm=v!Kct0+D~wy~a1 z;uk8U^)p?(4LK*Y-Ho01+BC{>5P#qg4?`u=zKUT*5w}fiUd$Ms{?q+blUaY*S8K7_ zN?x#ByrOLB(b0#hNLR1=JqEMatgsY?{S{Frc3@P(&dLR&e6aH3Lu#sTrT7hs$J-l0 zV%;Rz@me|y%>ijT?lQavAex7|@+93G=+F7o@p;2Fg7JuS3H%-Rs@;m6_4}ehu23Ru zNg^71nLF^sh9XGyqdT*hQ#TYbUUZ$6%j4rF1or*1MhCiL$ZS5PsjcY6^wwI$Y2gZVtH~^?uKX8qmVa`eBl# z#J4iO**xqtYVIR%_)@FHQZvjUBa+$jcx(wA12Zr`(5&i-($B5X!x!ye&U4bFMHFFA zU?{CEM8q!>q)#thc9N^PZ@#YFxtNV06$0KY%_5OB^etKCckj7_RlZtR(M0pn_Y#^c zC_%=guV6jfU(qlYyNzwLanzK8GR7%KyVjbdN3NIk*_5)#63{?};;yrtA#Qm4L$_vQ z&PN`YT?r*^LMaGcO7oyB-9V>lKfYMV&g87r4%?X{&pQr=4hi|ogg7^VmE(YB3tq$e z)L>oyNhrUy5IKBmqb<>jO00h}{M)K+bwr=Y?0i)}rSI{>)QWhM z*d2Nmy*4SkL<)$JoKOAJG)57v&xlBUm%YvAL?5=4-|1xOCMV4}Hf9gV{uuECroLbv4 zhKHB^lhHzd^}N-R+2yB~9+4k%5OTsthOUKE_Bru_mDq&32$zK*4q@|dyB6YFKoP1* z*SFmVf+GK;WRkpKwv4}%_BrBqKtc8uvk&w26VhY_U%t64$b4MBT!K@J1hs->$Y8>Fq4ipjhMK0KPfJy@u=ipc)G_K^PxeysD_m0#%L+>xL-fkKGc`*Rzvkdya1s7OnIDHJi?caConRXDgmt^zuJ;C=8{I1g~q z5@|Xq`%*drI=ak)t@AM?a-$eP$i45%%30)~(AKs`NlR&Dz;*S-TUC9Gn820#1;T*p zTG?UeXjF4%-2KsfBv8%Fz_V2g4Gv*9EsVfEQqy@u-8NSFOw`ejOe|+IvUX4Zl5GiB z7&fwSJfjsMAQZG@nM|nd<@AuOR|m*kU}dRp&MynJ!@iDg?3REdyNmmLM|Fq|3uk=K z*EtObE~Zq7lqM#O>-(`0zZ>F57DU&i4`h}j=Yuti{-6d-9@#S(8jD#<4qbx<7UyWV zdk^~m@|qK+Bb1CJOIWbU(5xod>sR+q{^dT+(Sy{{Ov5pQTeos_%($RF%QW|N(S2gk zyJ5%CY5H}TNF`U$smjlABiP6gFck*}sd_^lcd??HS>-<-Z#Y{olIJ+=JrT15Teap4L3VhK;!PvW2dG^GA3!{^)j ztvVd9_~60150o0!)6MH(v$Dbpvk`1uZ7)c>tb4{vKvX!esw`i*G#_HD%LH2;HS}F1 zy8?=CTNBz7B&OpR`{b3c8>G73F4 zv!$YM6NFp?)j~GDl6eEsad-V&Z(}>A`Fo#tG!rFXNm8{Wi68>@x6L7V+2b?Sa7I%M zvBV_lXz_*b&$s)VoO_Jhj#uCsEU7%c$(hgTC-3x1Zn7%Fn zW~fF)vEK}&Z!;#h1t=RMCr4#Sh)=<9UVwsOqD2hKIp%4eUi$ z;I5QaN@D`R7z+n2ezi){=U1q$Bdqn^)DL(-YFZr-K;KNlk0^}@-8rCGb2soFrWfa* z*&~f%!3%QHYP$FFg)MdQDJDA3&`n76Mc^R>xhHS*3;Z3OO5aBS1JN65my7n?QORiT zr@^;qIPPaX-22Y=9- z5>m0#v_8_L`F>s}X$Y+LV1}%jrDx^5UeOF01#OOY`x+l@ zYtzMHf~%H_4}1pz#%CHYDL-6l0+6_Plm_&^PTV}~=u1RYzu^0h2vafR`Et8eR zN7#>p8)d}%3NhW`PQ}52q>4YCK?JD+(F28S)U9nz89`>u9;xr%;^I6X$%TBE=6vzF zV7hF@V%HJfBOOX_qw9_#;a7XEBy5MxC-MT)WK51?m>XIhYqI&{!UaU(LsP9Iy|aZa zIzYUD&Y#~RewffNH{)S-kN8Hq3H~%T6k7k)d0xMvbma0>^r@yPJ(bXmp1?P>B?u8C z%I=MqcMQF~xpD7L7jRf~$~aLqRnHCk*kM%brWub7l2O)vIY&)Tk)fd+(y5kFSqfzV zq7Q4MA#UA6dlVJ<zmAka-sfmV$lfn&5fe=!lngWxowkEJWFW_kpWVB83wZ z?Sv}5ls;L3S$hQ*0Er1zc6YLwK%VX{9r}L3gjh5Fv;S`MWO1f?BF7u<8 zdEc7MBlD0{emjMhPK|GCPg!iFvKIVvk*feg=vcaPZ$Y>Vz5hQ-22aGVKsbQ#LVseX z!JyYl`p4(Li>Q#O&|AhF$@f#>11Wz*nNZ$tlS+tS*)?~e)sg}l$E|==E z6qRPeH~W9=JDWcV8@8+z^oKPvbmtZo+`7iq0ecw`F0+gUhrv_t568#W-?H;7o7cKa zLnBz*g8G$5V>zy9zYBqTH}!X@{ou*h8~Wu%3*3;i{9JU3;rw;7ZXyInV^! z>w4Kp$_UsmDb(xcc2Gt~-X3?~77x=v#C3%dH5$|$gJTAr?gg2TC02vx(>=+OMn>Ck zmx;X#nQ2l^c5=gUwtH2AFX1G#%)ecv_~+MsktSotkrUrf>I?{q%(P=4z9o54m&9Xr z^pmtSH9kkZNYHh&h4DHRx~Ne9LO%6Q+eaj4LTVMJug!z5XodB+lFi`9`DP(b=C!ZL z78ICnd5mK;F4BZ&3rl$Tk(oCc8bpB+eLtL{V;8swt~%zD&fcJgzMV|5GLa3_Wu$W- zwamYm+cB?QgTj@D8HZ6Ha+Clx7N-b$&BRqr&9n35gQCNEeca_*Csu@x^PZk8aeP`U zzEEF!zzK2ywibvf)mixEv)Jza#?rApLo2lQX0Zv&C1j_lketZp)_o#x-TuX}x1SV< zx^#*QKYC6B+e;wD$Lg8NC z690A=2T~|DK{>se#vj|CRBabjQ0nMVtD6k}DmIW=S`}`KHx9aKVYN6)dwby(9+n|0 z6i-j`@E-x4?JRDu@!o zeJ=kjVrXlh%4%)z=%ss3e@-i*zvBQu)QoTFRinV=hul4y$*}-gvy2oCsF#0<8<4cH zq(~!;gm^P*&wkk{CKObpASp4G-OumM+rboi3NsM{*XNz%5}AL;_9@87PQKo2+9l0# z;DB8xPh_qJ%(q#C4TU%%L;oCfjy;lX)o40AN?Tdf|NU86#ne<~yV$l-2f%;8E(f>f zN&(O9WRxK&gkkedf24=gRoZ`A!Jdj(b@L?u-B95|r0Zzmm{hTR0WNax+;N<|HAmxW zLvJ1Jtz$cqqMZ3!it8}cn5rOiu1}n*=UfR<=n+xfPDA_OtFr#4;HZng8c!{6B96?> zexR?O2E(f5?Dv-AUr?3(G_!e#kw%*C%e379eZy$G9@%1Ize>9QEzSI>sj&#^Vt=ce z12NoMxnNfQD>{TP5fM+HCFqX_dNcUJY#@Qd_fT)U#6M9T3VUq&;FDw z?3*X|7x8a5#>h=2Xgg?odbsx4BD$PC0?3zc~Y9Zc+qZ8$EWkT9z`WzvnG>>tu)Hzq;c`C(FpSP%l2IA z6o?r$Kp1twL%(J8-at1p<=v7L-Mc7a|# z%2JTL+*Gk`#;5$nqUPRt6;tDprABl4FzB@IvKNe9eY6wn{eB0TeKIK*v`K7Eezkg3 zUUtfC-gP9iqYnzxSgL3iQTTH9;;jjn?7%IdMy>t{!{hI=>XGW2l7PRtbkr$#$y)Y0 z3kDA8tnACoF0Dj^If15MAgow1lxBdUsj>bK*_q~2fipXRw+qz&9Ad-QaBG3h%$olXtXDl5*aOzvDyr(Lhmc%rw36dQI?Bl~ z2_%KK(KRo;O3y=^vX#Q{ww|xn<`@YPbQVCt{ZAEV`P3So`9j5V|GEw546VqPk?BfR z6ZlFw7;tf$o7Xw_7`;0>@D5(@{hQ~e_+Qu-kiv@aMHOXus`$))n3mX+S7EN4&)rG_RkE=vBwcMKZy0)Ux2&qJLr6ojeMw~ z2cQ5Tx}yZ+DEimH;s5f(>Clabf>_0`7`2)gYR{;^ZGd;NHdE6&RLL`3UQ-yyWTieE z0KunCfLUNmm)69|!zb54Pczoo*V9k5Lo0*ecq@6Vp!LvE^-`uv^f`%uLMI@%)6V}alE67z>|2u zCU@s_yZvi=Tc>Pttc}q}QsonYP6430JEiG?%}QoKm*kVd3-k0hzQytOMR~xVXkA3Y zot|&DboRD%UL!B~uDb{9(LEwX}e-ThChTQ-k|$KaeQTH?Jk&d}?YzwNX)9 z;U$izpP&Z+{1VgV^Tu8PrpWa3A!BRS^-_>WkID%8GQhucg5R2Q^Zn^d?BnN4Ewgj_ z??V;p87@Qa0?zU0t28Tiu}Vt*hY^tO0612~eVA}@%l;E_{Mc5|?8{Yvwq^UaYk`;J zvBkc(V8F#8^j)%ABBxJVH`gqXWtRPc0Rf2Vi>{_$R^1UVKfv7a(Vj;`gSh0Nf*05Q zoHK4c>lL;pi`busBKM;5Kh6=!f}k+QWEVJC2DZPJWxdS5oxdDebyOY+P-*VC26g&<5+sYj zd489C!Jq1iQq|ad94HGTjKYvuM$9T&I(dDh1ZX0_-v#D5^DOq^GOt+Wgd|f0>O5v& zV#BhvwG81;OMfx=olnyHtJP%V-lYCsN(KP++_r!4AEmLK1>M?KQF;u-?=HHWr>nH? z0F$D{lA;*UpoiL@)8xSFt$RqJwJ}bb-g^`hc78kl2d>TK`m(1JZMr1#E0{XOh9dFS z83eaesy7`m6y$reK9G-2WUaC)`^P)*-(4T~Wi&<0!A@xYc*CAErCY`+37<}?cohWY z+mDRWZZ{@>Lp-C6X@>iC6~qcT=9`mB%>HG+5ny@V?@d1J%#OcUhMbp>`vX#6fKr(8 ztkc;F7*J1OXMBLn(xJY@89a^%>K_%+{-W^+$@BJGnNvSrQgPb1Hk6+0C*_H)#Ov06xfZ5~mJ8_48;vpPzMNH{dbR?d0lXeVH2 zQC2`t>)Y}DnMpe(98cQ$o9b^=<)4gQYqLbFq`#Z7KhR}aCT5_ZrXZF>Mgd?#YCGtE zq7T^p6&I*(J99Y3X>+!z})R`^~>#)-7(C?+0gHl4@e2d?M9$bM1DE_g2rHjn4%(Y|Y|s*YbRxq8_B63~n$nW; z7rtHj-DR!TxislO0ca1hpV!-Yu%hOsdO=QV3+82jo5~yaDYC$uKc_yc&{&ZL$o50? zeozY@Y3*f?)*1;FOX4=>7p&Ug%LQK2ES(KIM z#EN%WbW||Ec96Ly5`N%Moq&IKMKkQ{Njk^yplyZ){kmwUcP=!M)zE+gcfB zV#hZbF+@@el?CvPPP!}nw_H4{v+Y4OnZS{Tp z1UdV8OVnl61vfJ~2|Rn33{r*)KKN^?4j9A$-9tFSZ_44#xVn_LY>MZ;ce1Cn*L>Ggj;%pB6+5pcdKmQ8ks_H@+3MUcj#(>l^69UO`szvSyxhqVNei1d$kfT! z-x(wb%BLdpRrYdOC3@{?vcIbN)`Km=$eeflzC*#4!ot!u)6s92U35RT>R^{^&%*5w zuXkBc0Yp8^YyMYJ87VE88-M_kbo57MPkk8PoRChaB~jsz-F{ZAhEKI7hsJ^0E&1l> zjF&BuKFUVsEzIZJ+A7)*oKsa;_P!Ou{XYk#NA(v3NuYy1qC7_yb6()@Evi_(l!3MnSEjnn5ZtD|5mZ6p42UrSd{0wt*?A{ zEs$eBQez#NinwXYu$O$2^`CWgd&pxA=-t_zfn+8=ewvN=UeLHSCABd- z%3=|%|JK)EteBNyTlj6?!6%&yQ1Sj%_-guch+<8QTx=teQ^(_V%#e4j%?fS03tkFp%O2~7=g)3#k-INY?{3S_~VMG7@`s_01 z@n_yA3}lY=!rq1jLsBp@M-z^<_ChBK*9495$Tr6W+YC~(!@}EcKphVZO8x$f^una8 zW?Lv?=0&-7Fog!w(B%lm&nqkiIr6WDphL0r4 zv)`X(n)4;D$*kuUByK3AD@QSJ9jt&u%kjTj{%Dty|0K^RvHPjygoMoeZ~V8*s0+E; z)6G7{h^?VJC}2+ZjlVtl@U4ta?de^++@kRdh8>+ct8Y<}P%uJ4(N$Uq6GAX@q9U0c z6L_qV&82yphTdLI#6vK>d8{x9xV13Wr>eHR{)^YpzL5Ua^EatnKsJIe3#Ni{?bj!t zME*zVr$m&z7HwZtIcnHl?f)O8PmT~YZDj#AMegLMsfTr&ZDG$81Qd=Z)ffWX^inNY zRD5BSZxJ4)R71;a*2(1G_~MJDcmGZT-49seXM=3mcRs*hh@Fs zI!!AT=S5Xx(fg^PO8)+thi*m^c%g?vO+8JG8K4+035f>@i(gHo88hCIDvt0!8xt7o zZpNDBiy@~zRT%c1QB8bT77HkKh1D-b_OX@)`IG{6*Ntv%nM_3AWV!#5^_^r(JM&FG z+{GH`Rg(D`|I+8E$Adoze~@wbsR-*nOLmBk+&odobCrgJ4x<3*BY*B-pP9Qo<^wmes89pPB}M^Dg%iB8geH6m%PJYcJk* z@($fEsb*#;dk_`aoDqqQsoZ??yjQ$s9qTK`HEWj2XuU%ZkI39bLRk_WSl>mPgK~xL z5-CxYTwTB~#=-QvF=p)iCU*Vt6cg(nVArc%u0$jA%cRv3Me~*hkkA2;G|~nWzdh(m z0^?CLcTHyCA_$~kraaf9E2>gv0bg+6rOMA|yc`WWl&sQ0iK&;P%5VP;{=mERe0|9> z;LpOqXC;8OeeVH;tcwhYSO$F(_cqn_`7qe8$vp% z0n9fg7HF{RErb9#3frCV9(^ls{kU>@V2^|WH+hqKQ$6t`B63o(7{Ij5pa_rZ6blT% zvIU>Bnn_AYtzYqQ(fSS5vyEbl#uUnZQs$2b@r+BnhfVXuQ5fXMy;SsS-mpr z(Dyy7eYF%6gadVK?>Zvfm$c;GUob+FOokO7Su!>vFK4cG*;yM$=2p?8e(MpOd!#0a z9qj{DX@sSd%)!Zrl!tO53qTN>MQ%&@E6@67qea8h^b!+u&C|x0;}2QUt%P8KrP$#0 z%Sp~m0@_Mz^i$L%p?)$HG;@Mw7G^1PUN<-zq-RpnUzrjk#bySZG>L&U7TCw3Szh<& zx?>~`J3rH`1O$QM;l35Q!_CTj$s2YNH!y=#lP&qD7Us+yDOu8vw=w|{j@9JFK%DE)#XcKTv00s#e`40 zmwHnR-n9EZG}Do24#%|6o4|RSvW#jZwWn;8dXCI&J>_Cu*rG2jT*2j|@)Yj}A{z$3 zdgaZk3YQb_%NAKPJhjgga{_8v1#(yXgklQs0=o_DO%hhomZu(0EMvigbL7`U+lSTE zvWp_8Z}2j@c-3EK#jKz zhYMiox?Pg)mJp6v9?9Q+30jw+30JsVDy5lfYmi-u6yOls;R*U)FYSO2`hUkts&L7- zT0{VuxsK?UWxH~J&I2+49T#87kU90xZs&{$p&rZl_IUWR?NYKttGzLi^gZO*%KNuB zT}_JJt0@H|`4#D*3X_awKu&wVQaEnKRfXAv*u?%=%~8zsyQJ`(WF)%f&qcehId{_3 zZhai@93SkJj3cnIX=t$cRLp>@ZkGvs;jb2!I6?dPasuEh@@@6`I4WkD08EJIKE0v- zjGycUCl8UD+&QP;&`mA`sKnC4bt@Sy%q-E9~w~*-R{+oF~ zq}#pB)?7jN4S40t=_sWzP@gnxAD@Ak*mZbeNzRl;EEz@V&td>h+Jv?gG+wt&uovy; zvP-N7P3j|%P{M)h7x%lTk*BL4pqrH7Rdb0m!{ONQA(jZ}fb;b^JV#XjdWI^Xx1 zwH7I$_4hQ-ow)uF_N^VjVSu9?CA7|Y_HNQaiWKE09eNRu(j1l4owc$^np8gP?5rv1 z=*oT_7iP+T3)RV@QxB)9#<6CIP3`UMJW7}vkhW$x}Cb{2-aMvP~`x?Fl6=2jiGR|O;g3+zlYXEv~mGZ z;Z;$ex`!yMe0 z`N?r{ylFo7h2-x-*}KzUTr?cE#b1~C!{i06m7LYt2Os^hW;jx^Pk=0?!u7tuuuQ-i zY)d$O)x>Tj`%C8F{?Qx@VGL#|rNdAC!$|uphF#Boayi$(ig!x^b;69*Uv_uVZO6S6 zzN+1HjYzjwJ-t-$WUT(F0XHlX{ET;)ouIYEkH~F}iH%zbj^xlD#HuRet~`5xz1(HN z`Xi-)d#VB2|D$kjyLHW&H$ zYP0h6Ml+0~R4-`KZm082BAly6BgFZ^&QiOe!Zq92Unr}O5}uo7=5OJl7z!!hw?Rg- zHFP$5SOf!nwT59CQ!lHnO~FuJ%Bim=r0I8$sw4}|Wp?MwL-Rw@0Pw)qM9}=J_=y|E z-n?;@5;1c;N+eaexorP8QTwcq+v8iatgZefD_HaIwPaY9W^+rby|s}T2+pU9ou6(K=Bc#E~sCcgc`TH^U6i z#_o&ve%DW;f;1&7=nt_0Y2NrnV3oV9P$12Rwpg0+EG|8)7R~nYyEp}v!D;7I@m$mU z+;&08iDQv-KS#pk8NS8pXdvRf_S39_Z6x?em`>m*U!DQPQXQf z&X^L8Q3_NNTv&ej)R{!u@*qoh*t@<)F!~pP(~`s`nLMu6hdw^rnxE`WB&+PVe)rGU zKL7buv(@9JM^&1Wkb+qM?;q}s8UiDsUk6M^y6HyEa%=y^`BlbRX*0z??$?Kjkl361 zp5eTbeWity#I(BK+JNZ4fP(^y-KvR#Y2{KxG`x(QciYOY@8uu_^_{00jb+P;k0_`| zOmHM!!nBS^@s8kQ{Kah~2_@0zkBY!KaHKjRT>0kxdEJNX+^3-0QUKB;f8=S!xGW>P zayC<6r;Ye~U(+%a!e6s(+_!zwD6^(ZL>&10F>NP!XO4=4t$(42X7wl&8p`|BJraPlJyK?KQ1F*u0fZTa)ZD>AHT=V&4a-T}ZOq4J7d zZ;GxE#X8yT_BD-3r6)Mio%~Ml^;Wr+{GxOeG1WK5WYk*sa%v6SvRA3PY)XnDc5~K9 z$phN%X4=Do?Qm+IjT`EQq%O$1ulF&Xf{ryAq*sB6YN^MG>i@+{Px~Rdc z*>oW3SCu2#a<#!lw;6cEf8S-_<(F@H8Ke zHuc&YIavh4=7W({S6!Bqj&Q$Mlf7OORoA-)@?A4xO~v4*`~UlJ>!fh747Ko0n8I$` zrqx=*3sX@QG9pX6a;3%JG0W8voa*&K<|ULF$THwGKY7kfwk7*fWc>UGR1g)UYZp^{pOl`t1#sF5OUXf=#l5!_@O_1 z?C1+IwNE`ag_3~!Q@PC4+rLiZ9FbkP6jM|Ed<%RuuDXCn95}Ndu1VT(&gfz_^6rbJ z=i5gP8?m2o$XCADaUCxAj(27m*1um6pKo z)%+uL<9$#$`mJ`|Q#L;T%#PALv>s?$jUH&h-#OU4SUGTJucd|9vm=~)=BL{zueO5z zGg}z%07iX#X?m#VCaWU%=j#EbVE=COd=KC|Q{Dy+o9Bjq>DfTid>4X_*l7^t0e44M ze%>&J{V!XkNAt<@CkdqtE*y;+lOz^4fV$+QfC~$=S0k%T^Dz)Q=u~ach8mh z>#uY=sA?+|(lyev_B_$4mj=8z_rF0H934Er+qryZ)0Oag^qyygdR8ESeATkaBX&I< zbk0jDr0g8BDYl!VJ9gnShHu6Nr3^$RV327h-!qvV-UPepvd^$an(_dR3jb00 zVh6!_Q*+#nOB5e$e=Dt>Llyc^5vNThM}%J>cjQYc?Il78kXN0dq&s%s-TUfl&uCWW zjU{<_4yrFXBtY-``=eXH?$>|1Q=6VX>`A zH?za%Cb~Y%H(Ql`;+MQnSA{g7EfxLyMzxJ?NX<5oI`0>^vX_r%cQ2>><16&>CAZV! zjmt*%K)9;nLV=9g%i+01#eK`s@4m*_XT`@i)Rzw$d-kk1+{^)3UwC71+5ifM|8*s) z)XkbFZjHn?^neYk06F!A4mwY0TCXNHPnu4&R=Yu=t79Cccq=yF#AZH67UFUJmm->= z93?4W9hytj^J6Q1Om!D^TA)V<0L20lG896NO%zGVHo#SdCjTxvuHi^~JkGvV!G27O z9|DIBTE!{M-p0R)t%YK+d$gBnp6(r(RBV~s?;HgRhj>O#541RyQHMu42$V38 z`G~CHdNPT_0i1{7xsG;kq?*QrJB1o_j0!JYKMSY6UdRqE`ASxnlqL3&3J(>lj!L5s z!7w}-iD+3oC`w6-Gc;R9+9Il1*PWED1kllv=;x)M?oCoaE(kHAi|RoSUwvc$X^)2p zAR$IqcZ~~;d>NK1&D@a38Iw~I`yUPB>)ho$IeU&HJg01Hl_~Tn&_I631l1Ree$yX< zz`ehw876`SfRUfa)Bd;5e$dX6Y)&)CHw@Uu96_uzr!@tT#Z}qqGw*mBvQS1A_01T% z_H+{%bjoqJKHXmpt$BO>uNl?BN+JJRw!f|;ko&Z>WDEt8=t4O4`#WJA`a;Q zFtLpjX z2mw8u1%)qG&osTBOL|vwv*NAF#KRAb4gL5vAD=*tWgdXcyb(2FAYb(J&9itFm1SBt zkaeEiWII0kSw)J76EaWNMZHf>GZH!}#B;3BdeXtdQZ2)*l^t-@gPd{WqE{)(pio|2 z&C+8hXZjK$0IVsumzYi;FWFXp^LP|RJF9gPEg&QuxJT_&AhS9GFPH2nXQN#H2W9Ua zm*oEc|JynZo0gV(%5qiClct`^wB^psfhI&&ZVbo)WDcrx8fs?ll+1Fa49$TksI)W_ z%^YBYKv`I#U}}kkaDFe(`}6&++xPSP+A4nt2aoSQ>|@vbP;Ys!B|Q`KC@ z8$M440|L3M-2-U-`jOz=QF<7NBms=_r|mlN^|w8nT1*vR;B`EwMc~0ODWi?rko8U* zS*=~8JJlh40poh5)^PgO)#sTFNN?KfyCk~pqTQ{trgUP+I?5wIq6E&vSuU)U4*C9$ z%g>)CnBGE8(7+vt<)o4dN2|kTKEk6+u{&2)Gkl!nZDQ#kpHZdT!E5{I_)Ywenqh*<7o7ZX zcH8C&|6iKzBXv$9q=02086hn|KDM2wwnkciEk%8pvEUY1Ucv2;Q3wfR6&uEa%T;qS`Ou*rRC@d`rqE%d;WW=U^lGdU!Fl+b z`KlGCp@MVcvbq*R$(@C2%0kcryEbqv1V99^goqe+1iT zucsBIPtToWp`#2BZADB4O(DUIhFEe`E4#GENZD4LwEO-yo>qYBryC}E&MwdFb)Vfr zLl6NR9E!x7(&BVJn^zVMH<$`bp~aJCh}A%B^;*2CO&clDl+zZd!OfcKLq(>0GA_9~ z%vy*@p6Y_Y_Ja?=mQ0TSVG`O-kJ$V5@61g@QD&qW&=-f5Adi`rh1@%wCJTu2Th$*S zk)X7?S2Pth))a4+!r7(Dzi`1K!?|yBm6N@+v5Ska>Y{Bqn+}~ja<@k(k^GO^ zcTEMGQ8AHq1#78~iz2}l+|>ctF_jd+#3(6NKX2AGF(S?WZk$GQGv6_7g`@KPDTw;5 zdoEY>b3=E{P4SgN8M75$!`si2tcSfd7rZ+I5y9Yh6$Nc#sY*w*3!Kva)gMipWy#}h z-z)R!KC(MMT741%AHFd)T@fO`%~A>(0Y3~spOoGQglg#cYH95eWMe!DF z5Q0yt{<03rjt+2DL>-#l+GYI`>u`!1UwKdxWa1A2I=q$u*d0@o-6KSUv$AC%6%N{+#15D~Ho5reG z#59W@onA4@z6vW1BhRBt{4VSa!^;}kPh44%4zH?NyZN);IC4}o zLYe-ipz^5xLCZpNH$_Ig%Zf6RJ-C?#fme44EfqG7MZf30zqIDwU7?jyZ05?3)f;xT zQ_7G+sZ>r1K3e$IEpN}$W?{IARcVrhX&yXcg4n3M7l67bVA{F!2ZB>M!&yH0wv_}h z3ch)K)x%f&aRK=nC-CVsYy8$8sBOLBA5R|~rys0g&47Bu>C?9JaG%RFH}4#}1V+5~ zhK{12@LuNoxNEs2q_dQK3MBb7ZJ*vR+gcDJSJ~GqvYXPKZ{)z+U)P;E+A`&b^=h46 z!y@>nQ&U9O^(Mb{GcCKB5*ySoPf7B;afWYntOxuW0KwRJ(Nk5G!PUN~n((u2WQL9{ zYqJC?8qgs+HJuWArvnhxrYNWTr&pcnKUSM72Q`ZN>HQ92*c9Vq#Ayp*{uI8B{WE;> zjUpU&W$P>dwr$f7nwsjaH$uf56D7-GSfZ7345;e9z(^$w4PViI&>aEV?7H-(^zX5+ zkbqiFG}CcJ#OZB3bA{ki&yIWB&b~R~VWvTp2q*zK#n5ZLTE{n@;VKQ+mX+1~R#AGl zW;z53pd*6!G}Le?DAe$Uh}KJwQ9XoXD#}w1HhzX2|{}R#aW$;U8&6Y990=dI1At zWV*PWiuUf8{_;MrN52_-lK%sk)R#gKPz2Qxv*I_fh;r`U14v){Xeai*u2Pwb}r3lBH<+8g>T)&r8~o(rvb?)Kks7XF7`DGCF&N3N}V zBbMZlI9b_Jsv6MoVfGw&yrLx4b5O0p`{d)5ecsYiAklIFVW6fq&iy{t$O_c2)5}u_ zCF~UkLLRHDjpaS@ud@4prqTYdRNDXP?Xf2Sp0|tVKc1DuRqM@6hE}rzLKJL&Cti;l zB3JR6}mn^8Lz3AjJnXD$Zd2V*`SG)|O=B zIN6vp%Pn%B+fPQ1h{Khn`xLla&LP%e_>L<`LV%!MTZ(iy!QHysUK#p5gg;8Lq#`v*g-# zCvaL%FOzxG37(Hv1N&HM$+fK*M~sV;nmffATnrfi@dn&6xrZwuDj5=S`7J3B)y!Gha zQMa$(+kE#>2|Aoe-(J)~N%;FN`RJm^yL`}MdkbI|S8hc}Rg#D+0a43yg%@`V7KK_i zPkzf8QeU^=-9k8lH+icg2_sKP9M&Df&F(g*Hj?iGnAz&e!jEU84(R5>#&|Rey#AJD z{fNhyH5z%h_*LMEx}QJ#K8*Llyfhz`Fzlw#xwn-w?Bgzj7ASMhOJNtpvxXt9gtJ?N zKb@iO@gMbg-E>1!{>TUdZViH<7M4nKeqzWUdTM^ZOyO&dr=$dWm|--#HQna$MTkEpxU`akeZs2gfYy190Lge_apv8YqzTvll2unUEMrH$!jDS zKO(d^jhUT&hw7w(TM@%QK7-9f)x)swe66eKx5X! z9?UW@mc{wXa6iDbIPBh^{mbw4uq=M&&j;cezN~KVp*L4T{y3k=Xsq|Az8*RlpPCSF z%%{bW9Doi11R+J=A5lNlj3%{uE%cNW~Z)_a5ZFKx-Q-1BXC;gt-FmEd9RYtC@EuZ?tMwEM(xN&Q| z13DkXMa&U32Sj~Rzd!x`N2(0*(fJDYDe-Z`g@b5CH;?AC++jL>kheAghMj7a5h1s1 z3SR43OGY}G@l|=3bnMTve&3k%CClqGARzdkD^I*n<1QJgkw||0_1~D2dO?YnRZ56?hTTz3v;8g7(UG1QtZSsfvZQw#{ zJ6V-$?nnx{jio{AoUCTz(ELht^>U%%b#_tm%mSmb{_l~qSsS`AtxB)UZDWNn7gh`q1{7Xev|&t4pXdG zA>0wM+Rj46-zwmr@?O>X?b4KaMgCU-0ZT%XYqnf`r@A6IYSIAHa6&PN{8<-KEiI)S zi|i2vm{;zN63u>KPFHig+GjTul<_yN3}Y{vc-kTA6s^_9fnTr!*w^$n2?{zAD70$7 zVqYc?)FwnhL<1k2ZhqG~qgmkC>hkjFS8iU`#D+%(DB$6!{AQPd#(v@#Xy(Gu0v_C= zD%!l|od1sxc1Y;h1=@~S`zs@gz&1pwZR=+e{kGRIVw&(b1j#Eww=vsQ5}d=z`P}kv zu|{2i41VI!W(78oQJoeIJWf3=Z|=QQ*gtAkDAmEA z!V~~+GyI;LdoO2ZB+718b?>son~rJ9!kNwsk30&Jd8Ur}Gu2}wB(O3Ye0TiD*nzj^ zlG2oWgZ@FI;LvzPA+j%jG~J?_6Uw5ZCa2FGw>XW`Gerdz5=SEUaanbHaU@GY=y;$` zOip#R!N3=)R%{ESEo?S<#!iM<$ZyZu@CTT!bd!|aw=MOXjbEG8-IC)1Jf4cRkmsMB z#>~;y@IdAWYERQ7cJ3Fvl|!0yODw0w z@k|^f%mh$r38h1hn2Pdy6@BvWlW<{czzD^EKmV$9W+v(Q>2;*K>S2&0#zv3Iqr$Y! z?T@0(8?>to&xVd?c;+%jb$6{&}+I{CQ00@r5o13>m_|6h%n5^Cf;`%{z*6jFNER#tV__ zQVS(`!0cUqlF|N;n!C@8RozoS^1A9^Kehu=(<{Tbdd`}M-4tArRZB=9pc+w}J$AC~ zD4!7p{wG7jE?q+8|F$J{XCTxr9JF4|tTb4pdgpnUW4x9gMxaiOcwp5fk?v5hV>E0r z9Gehmx1m@Rpx{-xdKUH}pyhF`vo8tcLQ|X&Z=LNVSxM1e$;ZWF%s-Oy?h4F{Ta~h1&DpA4(z^hgpQEq zc-4}=82!D;b;i6S#3`cOX|cmp>!kIE)VFvveVz5+&lLpY*TGf&H#(3XdlVeyWONPd z8Zq*S~xtTb0$a$>|N2WI-Ft;32d0*8;dACZ#5)e!W( zsG4W{Dp?lR4w*V8gS?Ok`+-u z(_*gMnO7^$DmXG`0L{CTQ(66&w|kN7)W$JZOw&qUGvR7eW< zDQm%-fnSDipv-W-C%&=&+=bci?M81f#7>nPS>rhALa17@G?G_X^7Q?ZrUBZbpe^>) za}PQY50#eUIB9B1p`aY>b!15q{GTPyfriLq%#Py3m~dWP?!blShc1Ji5B>h;#0I~F zww%RcJ;%?TXX1n$R8tO4Sx(Xbi9$ z{Y;G|kfCIGfzX#S8@*~13q$3eaSe#o>$hgOmwPnyOLgTd+6RtvY zkQaJ!0T^EfPcOF=6wr(H2hERYkaPCuYKgTg)xs+J-00V|Kufl$5WKd7GV7NLj>Er{ zFt2mDYpCw65laUD{{kIumz(bzKcZ>qO(%Kvle>9^Rh_(awd1=5HcJ$2YfNPsX{okW z2`YC#6Z-@OVp9E(zBVp?N4oZuA)e`a@_#(_MW~^~VPgLZn=|U(zQa{HYQTW+cJlFx zu(Fa=wXi7)fB@)57(&B@ltW;DWA*Pc3n0+^|I0$vrIuvi8^br z&AjR}z>ZipZFQgkyTK;2z!t0?CT@ZIP4epS_{0zSU2qm-54*d&v;XzuL>^X3QNZ3r zonWmioezOv(DUj6f3A%x&*H8Ujzu~^!WBKB0;ebr*$o7rc{Hq#9|d#9VOoGOYsJsk z-ksm>o1#MbG}TgS4JLkV!sitA6U-R@B%yi0u(jgo*Z70k8e7r)U*LPz31IPpkWv4X zu#wshUQ}V>gmTyK8TnIotsZNwTx$%MWa2>Rj6eB}!F#jBK=UHyO~kD9D^ z+Ly-t{bVk6=5zRo5eD;)-weY4GHp{zxF^$s!}D)A^zBo8aFODC{imr!A0@+ckclG%-J+8>;O8-5|*AGbL^vTc=Z zBALW+obvmiPTLXsC0cvm7B3mj&b`>BKI@xY>k~IXL1xEhk{q8*6geYkqSC5DT)udLhxWlEFL$TT7fwDC(KT*TYQLp3`nkCET3a|>N0@Ni?C=6#Fk?=^b9s`xoD=pmsVFsJxc0ebN`@VJG&KTym%MF5fKWSa>XJG6^lx9o!bXJc zfl-zAd4iDY-i&-Du{n4be`DM~YOv-u(rIsdyIUdWuj81kSxYA(M`DpB+w|rTa#2ll z9a1U5w!XT43!ke=-1aHY<5p~XEx5D=q@19Lr?zQ_HZ-_9f0{-91mQW)e(>VaHeMEo z88j3herf2`z{aIYVF50Ya{A18`N_IfYfq-rl7+y`TA|-o8)ejba}YK2^sQ{GlyYX? zBYZ{C2>oU|U2q9mwT#v!QI1t0G~%<(*28-7xk?WGu<^(l@@llcN!^t4E339Dao0s@ zZ5+n@BJAzPqozP&Zp0;>%yvt;AP@y5EKJbG$`x_h*7XbXXh4^mf^>3MH-5?ez_gR4 zhk2(bm5n43lIZc#c6**S_f*y{5n&ry)kS`W56*Ude46q~=;vNRW{`PCCTgryV_7b6^G(M4_4$s z%CM7+;vSVu)pNF$@`*-AX|jc=sl}7+)O~nDjOd9nViH6L!7Oqr5u`diePdV{^R$2p zFbaXm6MnS(`!6>c1_Tx0`KHi6$eyU17uU^7XEg!t?XP3zHc)}Fb0*va#g`$z@@^3@ zZL4h$CW?Vn2Q7=*cR>#kyu6whm`StbBdE#@+!c*a%e`h6rb$U$k{0Hd<6Zrs>eC3@ zcO;EEQ)dR4^HNp7c8zoSzHQLbNMJjnAOD_6lw`tyDeXnz$U57fT^ICX8o5$RvcXwA zYWUo_O^rr=SB4v>g65zk$tF~Ae#?OW_H*KqZKHUm$PTL#58#}1U#s5?gHsq|ymOh= zSBzQyaqPImN6{CXk>b0I9mXmnbYT-E>ZM)VcC(?mSi6TzI{H(|k>GPsN#n)saNuJJ zlCsmZ_1?m=&0PCyz)D^pyiPyr2EmD@B(ehlNp|;34a3eKYjKIGvlNhf?&V(Umk-G( z7Rmm=siRF==@V4f`hV2c)Per+`vUv;nWlAyW$8q$)ETO#TL#S7l$@?-?{VxLWa*|Z_C2c+I2$$!8NoWEk9lZ*LPFt1EV)~W@z7Xb%?=*%8{ zc4>^N;k(W$+9oW&Q|->(N;oiSKFXCQFYX)w596Asq=_$sjro%)9^J^Ry}E5qAG(;5 z(?`*6Lx!|?-)>W;DzNS+$(z^uvs}?hXc^N_i;mII>Wl{$F%>#zR%m{+1&?|3iP;~l zGUA`5b6cxR7$c1`IasUKR0#FQX{)3ouN?Hgjt+#ykBvI0-_?e32sqD|-eheCqpqI5hj3t%k?eDqod zj)Y$qid=^ZzVg|}6~#5oK)yU^u={&D3BK|bp1Z6=Pu&M*uJhBezS=@V3_Ab>k3rzC z#9=NZ9x2=t(m%6|A0Ol}B_rh&zVkP|oYK6K)r`MI-}QZ@%i9s^uyP@;&%rj5mOUQk z_o(M0>`pnHd>1$wGb|)vIFKw}c%w{DHgoy@b(9DbcIgjb&LqFRJk!R`KzC<=jgMrJ zH9B7R?0nhwuBa=l2QR9< zd{5!j;`~}IY5O=~aTx;X0x^)FZ6H+geU=Y`M95115e*-6I~?aGLM<0s#3)R|=vIoB z27M~8gjDg`a(B8p?SmHm7i6vP$Yv6%yb|Y|OEd%UHO*EaF58nV&V-gg;e$&ofMRU% zyO&;tv$eqcYPlg#L5{`2HK#cNUgv?njeFhCr+N4t9+(q=Nm|iJ}tk^N$*Hgo4ZFi6}XoywE1IAtsbAq zBZeYQuCA<*KJ~lypK92q@Y=dT22l%1-SPQ|);NP`6zp+C165WAu`yD!L%N6-hJmu{ zHy>$5U0=ide@q zw-m<>g8SBWI^_Ch@J2Bx>3{rq6}JRMHL&OkhHN~c9M3iI!<@Gz&>!*lny97F2cX40 z`vB_9$9J3&v1D(~FV6;$Jj!&(7<1K-TYl|XYFl2;`%(7zw}HJqo{#UB@jcw=lb%qD6txJ(SY>p^fKaMp#GBn0{X8UZ{X`E{D;J_gyO0k|IxMBb?iaqfSIk?Az4 zl#~_ZCNf)w+TJLsfIc@^JNyCML@P@(wZ=qENG1*wdmX{~c08`O=q|IpL!6kJb*R&5 z%}tQxtuVh}GxY0JjCP}>O66R4(Tk59+^j#~>d=2DCFR=)ZLGWDtrnJFqZBgSh>SDLDS2Fx()hSm`yYd=MpO+%(yw;Fq+a`y-QgSX-y9O_7y0#!dyV7J6r`ktMOK9z^YrF>cS@nPbZd<9p0S zV@!GsKQS3P05KL++jlN%LxWp{trk$$GUM@rD&v7(uI3IelNCYo5UPFW>PtUT(`(7daFcDo+Ah?RVih5K$9H5b&f9f6s>&_^EDGUGdx%alf`}Y^% znb_+jC!J6E>&u%R1BQ2*uNY`PW!s1DX@fUZXJJ9Wg0zwXRve9ItyW`+HC+>4g@VzM zy8WZ$IAo;md}K_H11IvrVB+;QOM(a+l*1|Hf)#XS{AX;K93G&OliFO7`b!Kw9NOi9 z5SpFh5DfyuTX{6>gCW6?nVDLc{(K@)FDbH2fPc+d`rR6diIanAy%snlbfo)C9|lQ3 z8~Y*fU}E}mPc2~lm<7Sv=@s8T`xF>t1s#SbPo}aO86Dr72E5I`=fg%vQkG8=i)CPK zpb1UNTCe9dXj#@q&yWyw0=Rsu|3AVt4%wPHA)2Pa_&_BxN>{B`d58E7*0rht4-s)IBp9 zf{;&6p#NH00UJYh^N2Uwibbzy+%r3RXMv39(~&JwokIzhjgx1J21M>1Eu8fB!WT;~ zg~?$ed0ykss3*z?yx-kHocxz3xA0W6tS6pQhDOOp#F=qMNjD&a10$8c!CAw6izNVV zAfjkLab>skbW3Coh&Kbl%2`(jpn!II-i!$j558P?^pHoh9TEcwqWd|snp+O6ubDNl z6I9kvq+!^Hy9-mOc31tfPul0KZjPQ!ET7~!n!7r_t zG6ITAvVHQU=-N$|1aO0i(p9yXD_W8i$L~7S@XE91^`$!_w&Rf5tua~qhja+>!7&*G zK!VG6OV5d~TLD4m;}(9qrqw$+gXnM*vaSQg;SYJ#;{i+v-F4e*rhXj>ukNoiuBhSu z*;RT_%H9V3Hl{C87zG2>5i`Uneb`Ib%jTZsxY~1)}mM3Ws4_r)~b7>ThF%x6k zjM1k8xY5|ceU<@|%VtfAw6~w@x34fF^3QsV-GFSJkGlBTD{I_-DDw*%Bmq*3Dmns< zB2vQqd7`Uqp2T~SPfrBOxKCvQDo+AK++JI@RZCdvP9q^`0}67y@d_oc2c$0}R=r zSMvx)4|3wuM5rJFDDdP_mP#G*mc0G0wX#CTQ27 z5|OpewDmukYr?4Xz>@JAi)~qL(Bk^BB}*O06`JBdQ~PVuY!b>+1+d}<{TkNq6RrNu z%2>~=5Zrxh*mIT)@JtkpsyT7UJwq08#RxfV!OzOuqMQ_X&a=*N=1fiRf1+)wBC*qZ zXG4qf?2$a0lp1j6r9e)powMVIPAn$OzoZ{@(i6H-BYC+5g#ixJI;2eh{{KdLi4!f7M3MWBsG5+at+2ZOyb>`wt| zqcam*Gfd9AY&IUv=!TPPW+cS#LUqZwNxZu@^JCDIAMH`d-fJh)Y4flc>Wb{MXVufo zpTFZ%n%g9PgXI2qqpS5XmumQY8IxN{=>EWCnbcK_^R_#6_p0A9y*?k|hrC-W&ebp^53Cg2VCIzG0o}Ty}d`17W-zB2KykA+* zXUr-CfIo$x3j$|KIk7HZo%RT634rL2_outr>Ip6honSAt|Hf;i2>^mD zf`43pgq)fF%@@s*-3+MruOB#5ns=cYm~RSi^bpcr8&m53;K6g5+@LwctzyJ9eT#zC z+=ia=4ZeTY`O%RPMVq)rb;yT1a+biu@;Uok2Arvip%que==(7xL&Y)0PT5e%ET)_POJdQ6I)r0Ovgme zPXwm=Nc@J)ApdJZrl(*;8EfyRvXN8f>d=v6JdPidOi_vu91UYvz&{xw`bkULe3jW? zNV99SM`y#@E7c-A?Mb02%ng=tSQ}fjuo}CF9{Cv>ccL>C*p*Y&uwvvELgf-gRRdq> zZt@(ng$w)}OMoV5$5gp)TMp1VK{FQXc`*D>EuueODSe8nr1?zA{v(m$&-5_`kr@i{}4)%$mh^VzG+>!k{Ah6XD|4 z0_WW{2&)3#7RdcYEfrD-1vZ7Hy$|-XjQqgT!qodB%Y9H>UFXa3DlA)#fb^W88c&t0 zxt;PSDyndR5D<>hC2jy)5dZy44%xW4_G5uS%AyzH+2ZrQsB+0xQ!mIG2DjGJms)G9K=QYbiG?r&Z=AJ(y zv>MR%Jj30aenc}6=XZ%3nm<>kX+?f?OBq;YzH2jMc@0Pf=ahsZQm^}N~{B{#9OWqH>~9ubf%lt*$$?| zP~yt!i=JtuZ)T(6kNi^bEj@vb-ycNwqxW@nS1q_xdg52SNiFtk&hwCmV8f8LV5S0! zg)?@Kb{0_{8D@vc6kz)2|o8;3HY%p_I{|$x{4B`rYJFVbcWefW6Cmsj10ok_eirs1oz041rOKNm1X{m(l{VI z11z&6D~!2Na3p*i``<6yYdbL4*LY34F}*=gN3THd@U(xq&ZTq9vrbl1@RMPR>1EHP=5dm*8E`y{7HKD0JVmYvz^9wq>_h_@WMOJLq4<*aohD0jVcKmyfCQ&Qgz z;EO>}Da;}uAQ+XmihEj&1)_Qx@b8^i!x}r6_!okNUo!+N?bua2>*f@u=w`-~@@_dt z=HS(B#exB87P3>6_++Lb0Z?}?t;!pnNeIk3Q5<8PB>Y6eK}+TC@K>lHIyILJ?Wo)7 zX8Tl@WCGi6UtKuM?3uj;4kzan$Ba!KY{|K4U|Op}Hq6oO^o)<`(`2L_QGefUuQSTf zYoG9{EqwPmp>yUoA84pW2!oMzS_Pc1Uy>AyFv+VmLbH04H**o}wu$}t*VMnZ_uZ3p zFO#hi+KR_1KhYA8a?EE19@2W1>b?&kQs zJFxixA#ku5+O2(SpI|4EJD^7?K^rLV8p3Y~%s*BL_u5W@2^%|zaDHDL;m=Pu`$ruK z_--C^n%l%No`JZ2Bp__ZLKQ@+ec{?)hz7Uc$4%Ne0dO*N%3qMNmYziT%fQ2w_KwIm z_3TW^s1P1>WEHHSn<7D=P4QeZRDEatP}#ki)l!ecEkULpzp*ber9<8o^N)vV#ZS)~K11;v zoj_gBlt4C221>9nWvcO=g|;ZG#n}%Yo3-8eKy`BGl3aqch95M)&iJJPYFCn*z%685 zYe9iH(1QGA0K2tV!f5-EfYl^3HIIWs*Rprh`pRSox*%srPcLn4THD8lO~zj!P?q4E zcmKJQXRMMwtn8V!i9I;?#E5t)CgrQ`6k!Ul*w5>^YDx-;Yceaw1k6X-ibvsye(xPS zyk#ZmR+_T#(fK_|r0&(Li%|iHdfzXFe@e=?nh5ZMn?NV;>vA(sxpwYdSFv3;1BUS! zU0qTLiPkBRaG5qfA(^nZ%imL9&oX6+4RE%zvnx*dPs0d<^us4GdzN zK6Zaa|JQqcC@XF30wEbeGPK*&yQTW}Wd+lY)mUu&B&PBG2}ACkVjQO|s&`*v3f3B_ z5Ki`KZ#gI)wC*_fhftt0^Zl%_-*f$yDPGf7sDbJj<5G*!I|Iw(eZdkSEbV#?de<#< zLws?p2%?gBx6u`$tmY+}utNdT!EBSHj4PSRv9c%&e$cyfx>yOhK*4t0sLN@rii$d* zXFEmjfeI0}zb+ap=RvxnbP)TjT|fDAA_&)vNs{moXJjs0rr%O&Ns?C5nd@#f<*@m( zw*czR6-xV}<0dM@$3_&%L9KM+o4730J;#=GMmOJAoHxzuL4CU!>e$W@Jzk%iXLHjq zd!HeK%)ZE`aJ1g~&pMzBpH&PNPkN3y*HyaT_T;qnZG8td=5`VCV{ccp z-pydJ?*zOZ^OA?oCicv5Y|>wi1h#MUOa)OS!cUa6TbRE(b>ZbI8R9&&U#cMx#J{gr z_RwvErhKIqjtw;>(X)HtOxzgJAIpGjQcVYe#-J*W?aWB*75#xEvQu1OCFA?#`Cf+~ z$u^?=dCl2M;`8av&fJrg4p_b{7fZdwoi9lUEZm7}E5Rf*@ z7(;YjRye;ewz%_xPR&pm>F=wp@MK!YA#iE?YooU25DGqH!a~4IRysHn`K?;I`pVL2 z#+V$DF?X~5%iSzjQa!?C&{?5lx5I~NOEcBWQ-s2Mb(Gw}nZCzC`yAlKcGQEPO6h}8 z5X(7;geVpfx#q7;)gR9k6b#K$?shW*OQN*DTqy#sWu3zetW-`k)%|3{a$P;s7V7mW z6f}tSko3ck-q~KilRq}n#!_;7IE~QmCa<48vy#aM{dJ(#4~|~{vKT?LAWwI;;%}9} z(yciCXO@kaknp4sxKK9qony|a`mJ#8%dXH+d1hM}U>3-#>Jglw^&fEg$s_KpS^RTi zX-}7BgKyMz19_$%VT?Z;_w>v+n%yfF%?-6}L7@*H9J|+L^U|%>BWaA%W9(+eHoS3} z`8q>4u?I{)s+!~{4<*@-b|~-OQ6Wgy&OOkqV_JO`X>nkm2Iqmco(gxWCO^{0*PrX% z$}>O`2VOHbPx8oEC_Mo>*%!B0D$cS)@S(fQW zubgV({JKzpLU1RIX@)`M0cbFuYC}l#t*P}Jzsc5sXwhWl>XrLg^Cd$pcHs#ZNSGXw zjHK3Oe%ecqps~;;mfa09C!L@OP8R^!!+f>gUmDbmRV}KV19Vd2J9PE!%!5e`&wd zl{>;Z2+w_?JzwYBTdQS?H@umJL19Du_49jW@A%BgK2$A<+xd_#h4;v?k}Cgw>$-iU z>&Is;IP%ErQ9cTX?1b}3hfiLg6x74*gXy^S@2BkqaFz`89ArX5EQr530?~(0iuopA zhIU}eHodWYmqrbkry-xD8tF|o+pG&JwaYe{lBrC_li!)2+w0IbLs}pyJAy{5?G#r( zd$cuaYn0M@RK4FhTyeG_-sOuN7Or5gH^aGvk7j7NjIOiR3N^~I@ekw40;76s$RT%` z1>5*EtSE?~>cLEpM+TQu-so~6Bh2q6Om+2d3pAR)fB1+11o)J9t>0Z7d6hc$SHf?l zp@&{zB27HiYXr{zBh+67-(5cE-&XC5U{0GBsfNQcjb8gyb4CEyetvFBF~&TA$ymV+ z{AL%hM`T|~OYG?*!RFBODWLwOjqXS%dfAi87$pc@{7qdEpQg-1vKvhHBJNzy@nUOL z3?NbZEsd$8t2NFTImKn_#^j>uEO)+XS*LEf(H0I#jen{F%*o#`qxpb0{ev5~{JNEo zS&=n>^IdF#-Y*CJ3+k8eUL3IafzJu~#}t-peCy7rMg-)qY_m0Q<}z+~UDVU2Mgw&RBTR z(|abo-&5K>Z+zj6C%!XTx47&nc@gt&v1iL&XDmMZ*z4co*omGlH2=exuVNp~aII;nNh5s+0^S?x{ z|DCGquC<2~aGD&Z`n$I}x>vG}Xof1NnkQNBOpKw=w)Hd;I`G^o+XO%4V%v1k4+5fe zk!sGM9hwHjFi@tinWXAM3bY=BM(I`|+W`b@l2;W1o|uo-Kp?P-fEQZam_-J!ytpwF zK$Q~*5S|U3e^JEGC>J)v47 z(i@r|$gSZ2uM#tLXXsb`$ZG4~H4=$Lp$R31@i*(C6eI%>)pNRhwy%3Wn}6AiIXM{c zenAjsx39!mVU_?Aos)k;niRnX9&>-6aF&nqW-Y{Z>K+K0KXT8ZT3KF+|CN`wS0dr* z&c)~J--%Asz{92;Lbww=xGTsk{gr|l_kP88$I}T1=#3rnMvm}dVa}dudbI<%+lS#_ z9>RawUvjuhtMa(vuf$>9+%_ra>G`q6r$lJ_zO94|!k9{ea3ckc&ze4m@@ zhDvTnrF45OfSfeauZrgAq_rix!vi2-tq~5Me9k*@2l21>=-6!CbdWiXtj_ivGN&GW zUaw*P|ZhD&ih%4=3Lv1v=CCEm{$6-0O@C`&1scWWBI_cRnMP z`UPJP;*18XwM@<1#JFMc0#?yPQV*v+^qbWTwn1JQKN;bKXt0kXO7wc1p7%r`Y;QF{ z4~AzuJ%1MwN!cD0A=b($taI;bU?9Sv!R9O00)lo{DPr|DAvDyLtqWN)k5qSMl&(aL z@f%43*S?0w8H(}9>9=$wGgh@iR`?{s^K~_#P))MCjwrO(Mo&ev@l%C);^4Ww3&R1* zLhAPBTf;{cFOq-m%a@Twj$AqMnpud3!xpd-c+JLccR1sWzsbY0DP9}CMV~XQ&}W$@ zvYPkiXE_wdyfsX3)(y7crdUbl?pSVf(={x{<5)8ToZ#>^M>idU(ERcm!{m=#Jy4FA zG6fa;<|r2H)@3nOP!I%6a^zOQ}T+y0C`bF;}KUWU9%K&lapAP_>ZLNKfEhgKL9N zrYVU(NHxozay1SeGuxgSsDTZ4!?#jN310Jhql_o58a=tH&=dJFOdw6ekerr=#Gl>Q zyMds8B0OmH1G$R=5BU3%q@szICs=)HN@m&fJ9963u5svTqT`^2gRXd}kvo>hskI`X z>gS2JjwyPSpejeSdZ4d=?hhG4{YbODAsNmZ>$80ZDuS?TlYN7KbrqBjS^^rV>(dOC z!N=Up0xp&pJ@5Bng8F(h*V@_YN%C*OM?-ak7G6U2XGgt={vsZqEKuM(mS zy3@D#Og*G^5%8%*TD!TI$Be*~O7)^MO$Lw)P6?Rk=pFM$k!_)wTd{0(t4iWgyf3U! zS=}L6-s*--?CI{&x8;C3hRAQ>z_jL;KDr`@+8`Nu54eN1FG3@eGvR@UOcuxtc3#!| zz$@87WVc4AtrO$RObN29SmF~aGBFN#U9q)rdwX*xcdu<-2QTnuJiCMNl-mLNg%)B8 zqdSZTr;I(>KIm}#wZtTmENpLlW>M;8vul{D3l8elJKcsc6Z>%*hTgn7lX@gXWejzA zh0~Si=~8EJBZ#(Kza>C2ZZ^5ngTt%GT;^$0hG# zuhSZmeunUANZ%py=PaINg9QlqG~mgq2F`5@&l_nM(Fo1C1mw}0ee^4jm(63XE&r_i zVb*)EJLr;2W+oQgQxSO)$-QlkpPUu!WKG3(0wW#B={s36lF7_RIf*$o!nBE4#kl;U zaar#18EM6LVr9rk>3kls$BMXnOXnBm44U6~ZQiAu7Z&zTB!~Fl)6N}=0mZua$rsgU zH>;#mpGf(eH`Gs43$oFw!$??j4%1lC)k3SWjl`HUE@L z7M!hH)Cei|Yn>FDmxZrkF~_P@y>ovDq&ud~C;tpS>$y8CvqCb=hyV81SYz?CBpI4M zXnWGrG{^=gC**=rCRri0aWZ;+Qenkv)g4o?=rwQjhWj2#Pe9f!c%H!({(WiEybrF= zrv`xX-k)~NJOUdnH|mO447W*w6u&2&IaO@;y>Y6!vGy~&jNlz|ZSokg&3~$}M!fab zVRu1q=U#gR50rbGea6Ntj93YkoZ-<`)e^un5KeNCvm0^^UN(CzT&?MeR$VK-Xa~$4 z*C6Uiwvjt78)>v8z?9|dE>g>sThKG(37bt%FKYW>awDcwcB?^*q z+VYl6n{* z;L(-hH=Fn2HSNk@(mYD92JFp-TRU?OnNcp+g0B8K3=@O>RsZJd z^z%;zwzO_4PBL_`eNe04c+j(lhB_U&o+7OkpIC9^2)5CMHPqluwnk)HR{szT;1Ljgg^T7hBDN){IijCBxOf zVa;F#cshG93eXo`v&(6oo#|9&nq#~7d>7wloe|t%W`|`lAhQHE&wOZlRrs~2Cb#m$ zEnGSXVdz?WO1F6%j-uvu?u%P@fo5_{0}XX&duViXUDh6Av7Cw_l4kx z_cra{XVB3tRRrQ&;ikv(u%wmm?l|5?iOYl6%JQy8XC6G+&3u&u6-E|IR*mlv=?PR4 zx2oJLwOsCQsdfPY#~=5so%W-x(|io5#15({z$U|xVy$-i&2HK{7S!6+@ zsaICHtO<@-cWl2$pZfmDnO+Smy9ISjnC(3?WO-xW;W=rsQ5Rkvk8NhbQo;()jI<5G z$rB6aFdfg2_c}~d!cB+_BjF51E&O=&mh7@{5OEZW;PrpW`V;=U>51eCf6SLmWu1EE zws@DAMqvR$M1O1hF{5#15TOfBPWQWGcJ?@}>q9roG-*mYSSv3~>U!{x+BEluP!dhQ z-MqO3STz@fb}|w)Vl>OB3zh5A#gd&P-?;rCJBT&*R^$%&;tW}pEKf>LbzVOVfuR9J z$oAJ@&ogq+p+p|B^~WyqN4KC@sT|uVRvR1$W6H5uMa#0|L8G9$mPTMlH~$}iQi7jvxL-^;fy$wqe*!QkY^+sJjL z^1Sir)<7H{OB6=pu+tu6u66q(mBI)9XL%Ayk^N81aH~&+=!^x$DV1~rA6INeN)kci zVv@&j_m@M0@?(C2UU0+Yyg{}DsvXXnwcs+)2-Nb*6K%(iGrKdB|4~y=tBlk&8T8zX z*G$ar@R(^=!O?*@-gyA!Iqg?V(dRL6-E2H=82NbL!h@iEgp&KX|F9@Kca1a+42u5B zug{bk7I!-)(MVQGuGlXolX3EVG#~MmEcue1SZCZ$Vn#fQ%s($EosaTa|2FZ2 z;ee0873fF>XriRzAGJ$vQDOIYzh$Dk`FXXM#tz=7be&^%cc%^eQ?)+JY{PuAh*lEJ zKWgux&6DXR!{~Et3u%j^*+oE=49uT01v9n_ufk>{qc7>%fdDQ{b?Lc*g&uvMrSePP zx`~Wr2(hu22jh}!+Xh|Rz&$fTG5DB$BXP)~U3o`!`0PB-6%amkeQ80|2#!04mMWY$ z@6W5v2YbCJF>&F+y!Gg-@3PT*x5=<`Z^O~sN8GTTJjmm4xR{qbBdKBc*qzSsAD~R_ zH0e95-*uPCM@;;EHzcsacRV-bE)at)vGeJ3I8!+k&}SBf#xResxvu~@WL;Cz8r zin=1BobL_DTmJ`X?;X_S`nUVq8}Z|JqSNSD^`68fu$K7D#Oc)2sbJHs<43pp#_VZbG%<59F840b4Ly_xX* zrr~%X&$|AHTLFsU7UC{^y;;}!c+&ljr4UZ->&149u}h*eSldrk5`KN{tMz{@rBCI5+g5tintvQF(;?es?P0>=YvqjuR*?;Om3 z+3rAny)HkO#!h9zqgRt%g$1Zf3K!w16W7<+%fFYIxu5U z%sBuE_Z`jOsvkC^nU>13cvvk^^ahq$nHTj@IGlvCDVqcftD>gI|%09-wg zV+B8nTgk?etKHg*$v|~O(SRr)B=q!OpoHL}&azH>a2#B#`@F8N*=Ji8-50%rc$X^c zzd^BpSaXl8(XQArzP{(thxUDH^L@HB`2(K@)ETNTFe9{ZfUofNbF?{haU#eG{T zCS6qxb^Ob;ZvutqO@d1Dl$mhN4?bC``N+A?SMI5_iPRTs zHmkOPeEmt%y;F}({^PtCloJb{SB#oma2rBLVHmKu%XdS_L~XJ(w#uR2Nh%BBiI zklW>jykgF00=w{8nobv=+vGf^@Lf2scyO5xs4H@o-s)jr#Amym*_O8~MFRQ0?)s-w z1JftZb^48RF3am8e-+`_yZFJ63CoR{0UzoMb3!gX@bc!fd67K_6E&YQG|^{CaJXuZ zclVK8jvPA7DkyVOoiGr&>}~vk$n>!5^Us+)*EnP+C3pdj1Z4a{;QGA^@xp#VjUHOC zS`v%|%7<;ZC2wJgx?e zDZFrrzBpOK{|b0UH+x3Ts4!ehx@n+xC8=7uC#Ls$Ka??b!TYHge05m-Gf&lu%~tpc z^;??Ci$Ye@YM+cMjz>jWMP)I}9Varzj=aI$ZlS|rKI9dvCT02Fx^wG_{^8Dj>a0U( zZEtFNHAT^_m}>tL)qX0R6$&Y_gUNViwjka59J&sv@cazFZ(tvTO3~#!$mj1FraVcN3zS!z5B5yj*`-%Vtb0(&VYTyRyPytm8ljza1A2h zNa$Uk--N+!E=FJ0N5d2A-G5MaLo=*d3htd3LdmPwn-(IFkV|ThXj$4U>2o=R2~nD1 z+?=q5<^mxlWphyoFhlF+;rS(YnxtLkCq|gDD@7FscWjP_mx5>jhDRSk2@Jx$`Yy*j zZu&s$bQ@}c1&+&j(dFCIKK>%ZeTj(|zvB3E-Sz=PP={uXi$mjE=>kGnwO(C{Qr;rX zGdENabY0+Z<~&;Ifq#m<{dm68pjrU>K~F44>Ypn}xguqQf2 z;;`Sv0=sb*q?~VSEWHZ+%W9IoC`)9^-mD0N8RDEBJsQv+*5#rGhvqfUYDN1oK>d+Z zgA6OZE=w)E-cG}e@PG+ma5pl_@^vY$IDf3}VUd$1AXXAqb_ot5>+`a|+(LLvGy`Zoe zUyL1$gs{L+Fq4DKha8%lFj9SkWrcFx3_|bNnHDX?I+kgo0R2kJI+wrl>ddK*U8q30 z8ePI7oog9TS|>Bt7Bj%;Sw?}6jX(@ocRty3XeI&sa$-M`k6(JCU3+~@L$pL^Hb8H9 z!iR>P5AlHE1M!-A2&E)A!3K^+uCtdGgJ!Rp@&m^11Qqvd;9W#+`D>{to-pFaRlHkj zKj#;?7F0z!qu9QQRdIAYf}(V^Ff}im2F?cLuF!LF-PgZYrsW=&^q^%Qcb<^Z8xa)Z zk(_IhP91rAQ17y&xf;ZJ8Cl+X0cnWS-7QUquAJLBW4XY~DVv-^S12cR5_nBgL>IYC zyWp)u9jI-1Ca0Z{f7ZUuT~PcWl(9-mI6@j29hqVu5U9^GtE`_Uh!+XBMC&r-Gf$Zx zX^Y6i2Nh!fGBg}&L6yzLvj=H@5Vm8aeZH06al;Nurt0|Tli$^4KtJ{SD;6aoP5EAp z3p`Q(iPZtFwN&qQ=_RxnKmM&k?i?ii3l{`-wLB5iqs4S;URcoJ&bDzuJhMsCcc{<$ z$i07R3Jg1{Xdn)=X>Rq!0pnUm?VQ4UI_7!jGE~3!GL=x%s%QR*2*z#MW%Um}mbb3u z@6+PUxm9THEXcCR^*}6Bt{~aNHV4x6AFzsoITXC03=;IvfzLJ*qUo2L#YZcAXxJLJ zNz`Gs&nLVoR#ACv5v5=288qv!KV~H`38fj2_yFOkh|NYSqMOIOW1C}Ke0;nxb`lfB zIWxBUoW|KSdgwqXrPLZC1;=-JU&p9OBIBU2;hcM(g9GyEj6u(V0YOXoZrWkzqD-2u+vIYuGI)hV0S+ z4-t3Y$Yk}FwFXmZ2a^oEn&IxYPAv(N{(TE+s>yFI#MICMjyi0G&3sLCDzz1PDtzhDj z8~JKS?--+&k@9dzQo)zy6RfSj_WoSV3^nv|9)brAljd&76%ie?CNHC@$cNl#QoI00 za(tL)N3Ff9Cg4yo@x64SnXgAZHQ-OKPIB1!(HucK=VII=z0tj|Gp2vYJv!^C18K=5 zl+;qo9phIISUq-j6#7Gnj{dkUw~q6T{XUb>om5a;{~%5lbzfi;;=P!FZt!l(w(pYd zcvj+l=ZSDTOP@rg{`hL}kssy5gajLN?7DoOZX;UXh;8|vETxis9t(^`M=QECg1`&V zksjM(w&o#k6{k>}xxa&X0>f^?m5%L+aa&Yb%&Ib8F^HWG2|bu%UPJxPOauecC;q+a zRUc3Hq!RLkPzT64pa}mVmXN*c2g*&WL&C_)*H1+DMaf z)&)O?`=IWL*u5kY>iKzaWp~mOV1A<{dlrPJNp_;iy(q4Oh-NnXAR=Dk#g$u6| zdPfa*Vn;~A!|qQUd<@k`9?QHkZ-e!z;jUYe-Xo5XySqR2=(jO-!9fwrFAuCMTYG)n zsrPlBl?9>3c3MiS>gLgWFxC&6Zh8JC{w?BAn63l^>JUKGJ2Zs&uW7 z3dtTil4=VbzcFL3m9A*h){;fw!0f!K-I#T}&MkV1S<)hRv-x+GemV{6dEzmHUK^zy zdAQS=PUAOS{}{jS-oZ;vG(U;2B*N zkQuXgno(UBx?nH89#j(7wH zB9=#He)L}OYfsE_BHd(b==M9|@K8BV@LxGzna zNbB7II%-7+Cz9xNTi}T@@;e90(Bcg?rgN{I#XBK4+OhUwquh&Dlu7?r+ zB95dFSG3BW^dBa{Mu?LN^mdkM>6#Bei~fJzQ#v3B_sE(WTM!Twj50$3P_``~9D8vb z__8nSQDpYpp1zaJBJjt$BnMDbo39E21}GB;%5~1^oj(>zdcnHr^fnL#WZL`XH)mn3 z4knHazIiiQFM!~QmP!FK`^5-(0HFi)uD`!>V1)x|rdB{5YJOx5@Y4O>O|Aktyh$kC zdE)9LMWN*8($#wj8qzZFA}!<}`&heyAN)vZ*&TN~v3uo6K4R7R-vUls1U$9=%Nn=e zzN>YCOSeijpOm{AiC%9hr>HN^;nr`MX10+0s| z-uo=QJ~c<oIPNN=rE#nW-Qm(fEF=|q|dsE!kgBC?{W!cw?#~5 z?jFj%KfL!_;1b58a0yKN#3FG!zs9(5m|TD_PNKveFIWs65bYpy93!h&1~MC6!4K=kEqoKq zF+dXrOI*Wj1qP)5&?W~XPVCRRKYGf;H?v}k@lIPhW5@!qHK~mX{U%6f3or1r1!%h6Czq~s0V`?x3qKNAYvbr1 z7{zc$WeU{+x}_OFrzmH(H(-jnS64^rQE;KcPH%IcnSRJfFSrAJT7~jX_0&%7DaXgq zEywjLXR+ViP0F(>zh$(ijmmX7Gb;_0+?+!r&nib?ep%FlC#TLF(+s=VzU=P#DqzRQ zUysPf7F&EcT__b`=B4OUly=R=Fpu0m4vIOlkgeU(Pv6)=L0dh1U z;g8|=RE%yi{ic?D@7~)z`?IRLbz{!zTyt)qQiF2Xi>5zqm#`0rPaB_pjC;@fCf^|Y zO4x)C_ii_~&^X$?BK`*i3mv}HixvuVZ0~Zc4ERfphzjcM)Rz|~a3E@C!t$W$Ora+) z3>da){L&-*L1|doTqlFr#pOg(Vrlmi^h3-Bl-~Nb4M?{nRY(lmI_2{*dj`8pW5i*h zDYFKA@T@VEL2*$;uOBXZybpJCp-b?ZTod*2_(l_S0yC*z36=PI$g&)|u-R^mLpXX_U{Yo9_qXHw-PxV(9tKdRD!ZL`$6cyp9oRu`738byilaf5f4iD9M(Ga;+Ine8DW!8yn0Ci;Qz1`i z)(&k^PW%PB$IV&Ehg?<)HjI_G&yk>MpL6yMbcP)$SbMs>orwW+&ADcDipQL%cOgd2 z-#sXkDvY*hl!CW^oLrA>o^JQsZkMlB(pDiFjBSkg-B!FqoVa%UCt}c(+{m4{m?2#9 zM!MxlcDz_hB*&F=>OI~ktX^b=jjn`_=&hX9lv%gywF_370-=FHU?J3>x2y4l?~&SG z;}s|04fsy(THvExAs}-W^thHH@6y7(4m$^BZT&Gsd1u@+_t3_a<$GyAn$6ttA-MeXHzXVG}4YMLy}I?7qyU4d;8l8|cC@BPO^(G3@o9<*Bf zVWC{LeGV#%eY`xF@X^#@u1Pg$d)AZC8&WLUd zdcv%o;?3tkQ9os^+E*~<@j?=tOd3s#a8!>e$3qiB$qi%4R>AgY#W7j0VH+KrROkI& zG)~XupPSI5aY>UVYqyQHsLx%o<k?N#3k#htA$_{C45ET@ z?mr?=%m?Fkk+-(e0ndRHv(TK{%QZWKt|!i+N+vOVo-I|~p+YAAx)eol(R{Q0Sy(>( zkbcK>oev^b)zo|X<%uQ5grFccrHpW+7MpQS@e}s8)o4Z9nFpGEIac%KyG7#yXugfX zXFW9f6#gH}&Qxi%sBF;F@$cG>O;f4zsstZaStK)HoBo@tXX%z`DdN?m(IM@(AsRLz z2mI)C5y{!m1-WZ)anj_Kj5A=KL2IMD**_4ju{i+W=7;Zq6<_vl-TKPamU+0H2F`c) z3J{gcmO{c4YYd3V~jo-6=!H zR~Vi&Y;AygMD0eTPwgY5{O!Zk?Y_*Y_?7&H7=_lN$2dz2xE!3QkGv8h_u&`G+9^3C z#52dJ8{=Xd$ZLbO#?-F|x0;Pw4J{#J|Lh&5?ipsrPI}$Q zpB#D*R)R}JN2jNsw~7>uD%+`~A1=6{W{W%bMGuM9IoQ z1&5Y;mHTIE0?6h$g8nRHIAcIbpsh@}kFi0%j?t%EhOLi*x4Q!(vQeIAR z(LU^5cFVW3&_2}c{a>(^A52T2;;Zx9>BaV%ys%dIGVYcCGJOFYoYWiho3#^@+kDoD zoO4PMaEF2N7aKX?1(n!wKx#bt7t%|uBVbwWqYw^z+q&(;(`e!{hsvU#I^dvvYs-31 zxm=t@F^(zdaC8}YoG$t z6NG0X%MN)RZQZrp2q(G0996RFwx%{@W`iVdW@#X;ZF8dK0&D3l^W(*L2)oFv`pc5$ zqqz{#>z7tt#abMf&exwumqK@UM9$^@>9Eo) z*DAv`ydD=#-B?V_pL-E6Hi;H-p;4PgEH>Z-7Y>6b5C#Rk?!&M{qazGh7r~P!2Kjn+ zkJaoE^ug4WyjU3pED@N;nidZS_#W?aeqIf3!X~({X@5b^kT75kfY|(maNt#OhCvCv z4>Y%TA2*_k85GQ?tSY-bjh-CC96GfUoU(VJUt8`Lq*5oA>{S*)H;Mt3v6Ve(WXIouZv*4{fOU~h1vf}Z$Kaa9Kw=I=zG0&JP_p}6xUMk$!fi>F%wMCaAwW+!W*c=N$2WyR4~tZAKKkq zdoVU`jLhuz#hgjaj7>f4Fm5Ic2bQVEF^NJh+(pmM{}a^9Yh zY6p|VBxUJ6hYx2QE1@T+agN|Co*EQGd*NX zh)r09v%DtTSG@ZWGuCv*Kx2~l`ONR zOUq1A{}+Pi()ylY-m;MakTl(O*9+42J0yoqk))Z-f85KfQFs1KKIudmTuka|Q`YUM zx@_I6iCilRVl#hjGY_(*+CM{DSapHq_Di4FCFiE3V=*X?`qXh+maAn@6cpT6jq}@* zpMOI`q=-uWa}z-z{_a&_`qc4v;pJi)T4rLxFOR0CY3?$F)TK8{Wh^{;D=mjq{y4b- zWMcCgyyI-`?6fBKq1YDpI(WL~3+1)*JIH=y@mx$QT|iQq#vYA%0lf~*rNs~YUh)YP+aP5N+@l`eeX6{@Z^CJ|-WxXEZk69VMXqSfQ zU;SfBZ%-Qago|9y zFFRY2%9NY4KAejR3yAoGhU4QWhV!^U21hdOinWlH#9#+L$f7H`rHkhm(*_MUEfU(B zbBv~L$BJn&K9*=kIT#G?MZU-SpDiDg!U+a3{yiXZ;Xm~KI2WD}{G9R0+ z=$igk1;a}-K+taiqV&%5HXV5Ry8I;FRXTvqPh9;IUq*J7o{pY^2kvyDa@QQqn8FhQORfZc%6 z3Z51TfSZbCGQyVl^%u2OUq#`dv=%>bc-TeMtrb68^MHKc27(9^M}bG|hk# zlamQ2k{neot^4VQaTWa+Wac+$=Kt$gu@D4zZKh`ZzdvoYX|GWqNG0<^=vKG87%lg& zUcc=kA|MJZ)_=cYq>IIKr#IW|`So@mc}gd`f7Nq$d`Rj*`6kU$c2PP4LSEG@Be$iO za^{I^%#jf1x3^trY}`@B1wh&aeOYDE0l$GKSM-Fxemh7DmJp^-UMRBhuH?v9egk(j zzzUy=KfQ^oTb{D#S}xIZM02(|Z*(#HTsn>A zKUZn=lje~B)>8LAwcB$sv1ADMgctR(02SnyX$JOM)S|KET)6(OxMC~)utBY;ijYg} z)@su%cR7TMfptHcUmbN-ux_W}3}MjqZ~s7TH&*e{cg=sbF=fzJyMQpw=|gGZBDt>6 z0OC6}c1|PbP0WFQ_f2|d4I-p2>~os;kdH5=WoP=9dMy?>KKb@TaxTe~`YhR(0d%Xf(5D0qrNh1RX^HgA3q+<8>{aG5FowU1AX z8e65vBD$rFvOYY)w2IspdNqmTB12Y=KxJieVfe3yqyu@O^ob>~x5hSH`ZzX;CBLv) zU!zySk8#5SZt#Bj_i#MiFtH*sb}7&~dtsTW{R8_BvHVJ%&f4mrk^4yS8#Y|!?K)Sf zyt2FH<;p^80t`$q(KDn-bN!qkyn;hyoRmY=3hg}456?2L%TG1P{VaB0rVomGMq@`! zD|#|2=deULCAiERvG4iL*0mO)OZ!YXl3rxiY{*XUK0hF zZllD+ybr++71|92vywJEhOo?fRgZm<4PxmL7Rh@f_wEz$A~XQzlTIyqve=$sz4gUsmH1fL<2)p&;C^|%G6BvdbXI^C;=yHeS@1_+9g`ZA7T{K zfJKn!IxsWQmTSI9AX9gWv zlQD4XXJ`6n)n*kj%BK~$tl$DoYyb7_sPnXF_lT< z?!oAQhK1fJgw}c)(>yZHezEEx(ZnVZIge7wLQ6jNvT9Sd7n99#J7_UvqBFtO4CJz` z9@Mi|497k{CVS$7Ud!QBZq08s>NsnTJJ^)GK)=>I5epqA(HHSDR?GB=algrCgQ6^c zZuSrh+GtZ62IhOuWk%f#)ca1^ZcuxXI-6;%rWXeaLMJ9typ6l#=e0~|AX_#l;LOFf zF=rGjyH5qcpZTXz5*Jo@IKILP8`VhB2&L`N)zeFuRTe;2*zfxi6Z(H4Kl3PAb!Euw zH$(>@Crp1NS&gH|f+`Qp(wg-uRS>kChb0#6dg}Q$`<5RQeM1&nCuovf9^yEb=LB8u z*1y_ihVl~$D3`0g;xr1-`+fa3y&CgCYbhNm_|N4nHX-7ZsgSuYu@p{_kC{5vIg3rs zSF3!7U31@@w~YIe0g~#c+0mr#=j}aR9eDRYY)h^ z%KseCGR|79-9n3_hukHFzCCALMYjM{?r0++JZbFQX3xZHZW3CiG#f$Snt!aedgZq? zxoo$RlMT~>WI22UcPdx@2T$xCvEw;r0XyWO4nr^aG+qH5g(jBLjxb#3u6#x@>L)tgs5vnO-emwuy-{xVrmX zOc;8%xf9Jw%JT4WD8_YU*o`tDGzzWTCFFnzLm&nlpnk71%a&2(YFRJ#W7q|?oNsrP z1hO8|4ZBe7-f!vqneCF#hk?#uO$E}q_Eo3KF-@k>VGbt9q0(H&JYRK1FJVdm;$z=f zj%FK;7L#fA#u`HL0Rs`DswJlz8Dkg?JfG;S5|;6aAO6AjMgx85*-#pQvOF_=v)eY$ z|13`JGhq3+efvtHL9idJB7%+5|BChD=~Z^-Nr~t#&YDfj4V>s|pxJG6ijTO7_YHsC zDJOX#k~DbxD%9j_>&xEHE5GUg921N@9{+lSA02ep6kPdrDxBP|#Ym$xN;@T_Gg}{q zhVt4T(?;aFw5>PKru3Mf2gZ1C`;C)r_t!tZcWRyYhbnkW$NR>GDb$By+hi5nq;`<~ z&;WxCz-(`Qd{-bgs&V_dV#*E-&KeuTiin42u~CG39R!-QX7IHq50qs*2n=bFOiVMz zU6X73$+fA8R0)}andSaxZp#%e$gNT{!~0z(;ShEe85y$Mnwp;g`#NOz}8Y?xfH@X>wgrlQ!qit@BEd zf~2sL$?H@nK0TCOK_E#J;OK{V9^tLvmTD4D8Vq1fFQUNqRb+`!aB$#v6wY4@() z95b;&b+izdp+;-pi}p;?61;P#cww1{*at~}W%*21gMEPC3y(K;1)sN6W^dp}jc^)+ z;NKW$0?>8$&d3VUubjbL)uH0b34Zo?nt$DJ=Ug1`qZ6$@!y-84h)uNIFo$9_s*+w2 z*Ye)+CZQZ4HtYMwDM>mS9NhvS5t+Z%n*L}7|INGR5ibpgCb`wtNUTrq$XoPEfDb(} zW;pBY$kYLI&4J4q_Je;u({Gmu5#)Cd0-pQ{Z3${O;}VssH=+D?0oGb0;?-FHh__*; zS_kPjM04|@^z;n-g%%=>53hW@-ZLRmjpxT8^Z%|szZ+8Jm4jEUvYTt(UZ2 zb~xS~tSPrY+}HfZ7P@5+yh^>frRz9|_Pmk#GU3q5vz)5NtY%I^0ub@g;RE$=u3fs1 zpv}631+QljKTS#-0}*!%j()gjl}TOhl(Ss4iwE)H0nz+nmaEF{1=`csfqK%M$Dx|E zsHa(h9NLP2c!?V`kRC?+Hp~;TK3vPr$xO+*ZgBD6RXQ9ov|G4I*j8vGU1r8EBH?2y z(KNfKv`qSnHwMvK-`5))a?PMjvgD1uS6^3mr>2Og2(Y?0uWZxE~F; zL+JS=aAF>J~eR5qk8(6S{2N|f4FrC(8>WM&mY zrce({@r@eO-d9{q{f8cN1YC)05X{GZoBck>p`?Keewrb5ir9yhi)AF%>rHV3xNj(4 z46G*LiR0dHA8K@sKtzH2<&XsoZc?>Xay-r)D%sqUIxqzzlY10q}>zV#ozM;sCF7ED(||(cC#8&F4N>1&1BI(TzU82 z$|9M%(I|%2De3>U@a)vYG5b7SN6@myAkUCrTw`WhE`a>M1UQpuANe)fHictmL|c;e zpVvD5jj~xIt%a7T+5-m7OE5xfep5_Qe1#FwTm*Ji!uSCaC>XWl<~23gEg(EA zn1)9q{ubWKR`l^$B<6Ykhzx;rAxz`7`dr=`qN76F+NLGdCbyaQ;^Ife`;m^txAH&i zpfaqq->8eM(F-^X7&k>TKEi17fqu4V#PqJI@cJ_msI#_(KeMyEPq4sk>B8eMQj7;w zXMfGzd6TpsQbHwqt;y!`bF^Sb2={hSG1muR#kOYk5n`}zyx?DfA9ZQ=u9R*rLeR3A6j7CrwxkrOyFERQohM8nQm6 z{aacl0FIn5KpMkCc}AveAw7KgE7t?!?sLv!g=GWfF1xou983xacNLo*@)_~3Y=c)D zLcjv?a^=CLo!MA6(WO)d)S&%-3<_Kl5=W`oS-&h}49Fq8AN^L5%8W3nizuyqqb~EK zyfX++&XOuL48;NIL?bf4rdO=_%FF+;eJRfz8-v((&Ms>-b8IPVd?HX*o@atq7G--z zkB4oo5(hak4Q1{KSk=&Q5#uTz%)Ca_nmk11U3m3R7bn<6_r@XhDM{-gyFd;-d>-CC zruY2zQVQYGB3R%ew0nIW%2UGQx}GGFmaV>_EFIQ8GptjryrH_KE_m93di56g{c=RpM%6Vd`c=h+J;R; z&VCqlOujT2828W<)ED>_5*<0o8=@`L1BZmtwVAx6gr3;qrKzVpJ@hRzAie}{zOZZd zviCSX(8BkQS+~fF65xqhl)Ck%@PH`dR?1rF!ma|!s&Q(FnBRf0-tLD z6equfFY+#wd|CUwm}LHXquV5ql0ZvHcCL_By3r+lIzK_AyW*-7a4>tJ#b4iV*PGVh z1P}k>0+mGOx>e`g9Zu_12p{U-cOoFVsNSbq# zx?40p=cDPsP*GGmSOmQF<{%OAzXRhzX5jx5pYebAdoULP@$g=_9I))7;`v|J`!L~7 z6m+{E9C`N08Y=sIbx(hS%WqIrT)m%8=^7KC{`pjb=Q!u$@{!dkZ){+v5Yg=>He|t_ zKilhptNg!>%m=SerZ7!Bi;YCat9Ox31(YcwJVzm?|A;X*Hi^Hga8WY&<s*x;wPdKJrICWgXqk0e0VDvw85d`^C#|o zZdknEjp z>?bdV7Ne`Ywdx6a=FR2IUy1>q!z!ojVykO3;s<=%Slf;Eg{Aky!T+GLYb3!VRDgY< z2kUHTD4OTz(ivsBbdHR4S@IqIO@BeUspkTrgQ>gZwCo6HUv3SELa(2SnThANOPONA zX@t|w9EdDFoj(_V0*5xT#&5S*XG!TX3&$D(2XsSY95-rmNchh<+s|f|f(9yndhPn_ThJ9by3;rDAFJKkb%Lcz$^?3( znP~t**HV2pSSepW=A-i1bxdnz`g}RX!$v~F3{4Jh9o#Xe5#PjJVONS3p3iSPYfq*J z-8pe9PvFCy-acSV3yxgsk$b?Ig=A%46j|;*y(Mn0ke=;ZQ1irM`owt6Gl8wFk%HZs zjwNJt>3Hg;-C#CXwG|upg&55ISd#Fq4CJd4nSD2G-4UA z7+TAGCK7iQ9FOayKE8`|V9*$kghy4MOjE|?s;v8jxQjEQEa_}(sqMe3{Gq`?Y>pqm z*GtdxDov4%!(<$9e&r^{tOob;MTvz`>zo;oNGqFEeIGGi>?ysK zGx|Eix#nGUjm>^P-9e2QqJ~}eH4a5e3=IM*$;%CVhD5`Wp-bbIa5@yPrM4_R>fjxZ zW4$cgcy6Jxy1sos9qx(e2MvFeul0f#zcK&taX zB^CZ7DHtWb_YjewKIbM-_ajinvLU|tjc&(f z5h_)RbRBfBmFd3U6PpkSf;ddzC!XoATFR{rgfn^=fm`n^vo62)|9SiG45xl`5l_Yg zd*e8gYyAU}!M?N804|jtO*#=Ik-qo>Zg(>Tq9q~&L|^MB}_@c{o# z4Ff#fra@a@q^d^zyXw@w)M_Ww8T@lFtu0l&#!FN~?hs$vcxtOZOIjZ<9!2MnBO4ss z6Z3c4iV~n9RuA)Q-1gdJDh`{1iym3l^CJ@C9V&}hS46G(tQQ8*%ZQ1D*<(7MTrfPm z_4n?4VKAb^q~Zm=B^T2u&bC~bN+b;xXWpDyk0kuTXfdtfZb`KYTI`>_4U)?d? z&eD?+F=1U@%pYLndEJv6bG`S^q*?$}8zIz$G@jQYI_n_`~hAMT8E;uFB`$=HP&3lP9zcU~H(7u!ykKMh67|VU^AZUmKV^ zwwfHiQIgfc6OD$t(ty)8HKN8K~cI zGO0Hvwf(!QUY1q)mCaphTLp#60LB;5g1SPCITv9B*4G4Yi|NO_4mU{+_IAmL{?Al{ znaQK#Cz?xrNXsVda&!Tu@gB0_-b9n$a<{+`PypjS41+7wM}oq=yv4`O+Tlh%@c5GM z9p6NhrF6UWx7G-+j7rkYyxZ&oPMX~Yc2Tpe%k$^zJbP!jFav_Z;{$cL8@Bqaj+Fj}k zh4@_4+NlywD2U@=xfS74DzRxJm)|LknXtLv@zC+%S20z`%v8w2v5nHxw>H~;RV?yneqiluo(|); zq&&esn3`|QSy&)ONJKmu5<`M`x&Ff*UQN@Rv!l`&4v7~nVh(*(<9CBl7Kj(>)Oe1e zu?UNgaEF;WMU`o)n1uq%44fV4n5cDRJRHPw8hCt)$OsW1x|XucGzlirJHvaP$=gFK zO4@h(=p!|(&Eh&5rtVEvBFm0qbDiZDPDiVJQ3fLt*$;_>M16%-DlU+SM~;}bt~*a4 zO-lxT+{V6;?%kR)Ef+%jB8?wz+@WzwutN7r@S!+l`afV8IVsrZMVi2SgJSZwSO%iS z?#fORS?}2I<=6WbL$Z#?7z!+*&a=9#YL~ig|D;`t6UGVs7E;k(Je&RCS~o7`8D=#Q zA3sDJp~jIBKDIekt$XtAwt$ib717Pr)hKSHAO*C?WT$1_{*|*wE3%h76r=s_UKvxKO-Ix^Ej^KU#mh5Pj+CpdQ+FlEur@>Th37c-%>=fRPiiMq~$V! zEg-V@T!7w5(*6WQ8XhwX*=fDc)sUnA7uYP1RM0*)s?iuT^UrtL_k=?9%xNPPYeuf_ zPs$E*nKK%E^S%CWx9e19FfO8LH_^6%c)i_myMp&irPozMou}TfjdkQ3r*W|lfk5Wq zlMTo0_DHJDxPHsGi|Z+lB&(<7Fc22tLA8@9Zh zPdi3@&EX)FP?$e>`WBgE=u8?k{@gk9;#%tL#u1KNbOPU}_iAm1HREk!)~Kqlw;gn4 zsSV(q(ng~1tB;vB8nwSg&wC!jbI4KS~@eJ+HLV1qxuRpn$Vs>s(<>wWy~Cz4L} z0jQ9ivy~@EIWjig;Y0N zdiHn?Wn&*;*%i)?FSy79L3`r{x$-Xdl(G}KYKGII4ZUkx)6BbFMgG%foRNO7?Qu69 z-N6*Q9JquzMsYTBvK@Vf$!y4^RtQNja%}AN0Zd(zPPA@*0g$E;rUPQb%-E3hZ^6+) z_IUy|p*xj2#>#it(CU+!?Y$VXeEx%cHXP|$VPa~XqVMe;E#SD>6}?yO{$=e=^2+qu zi}BA62wUGw7!bKdEWh_km`8tPI&d}5A&Z5{QjlU4?~0S)4vZHM8n0+CjK{kjC7*?5**B&76uSLF;H-gpDV z5wizEi}F7k>t6wNH$Xmm+K+712{!u`!TofSrzI^%fxsMy|E;MmopL#Ee=N)v1o_>o zxA56M^4X=9zRQRk`tK^}w1j1~$6?oZ(cf1C*quTbwa5YApBHVpsqY+IdX)W%F;U+w z*R#q^6du*E#KmB`terF<(e#QI$v1MBO`16$_E{O2%^l2)t~Re2AZ;^6S8>UCLkr@G ziiv30Fu2Y}W?Mx#M#w)jN`JN$8RBcdP~W=Gh{^+A*20Hg`p^zygJqDXd=~yw)osjf zSsNZz%1DKX)oq}!j^Muiy9$dLsj!r&WDRNhZ#HXWeZ_mAW#q5<5lWc586IDu(l~k} z4BqE?4JFZ(Neux9_tn9fPX0^BlTTx|sS`z9di+&8q-HciVmWLjZItvS1~t+3pZedT zVU<#kCGtU$8R{@=na({Hq2exK@~2=Gs*KNm zAj!@}c?jY)#27@R=Mts(C@+SWMpn!p2K~+=QK=yH=aQm461@=1N^ZYznjRJ*#b~pj zaw)giq17-Ok{-E1vR*d3;gN#KBM&rbxGTw}?AoS16aN{EB3G8oGKuy7j zV{vxiE>w~tlv7VQvva^~!-%Z&0`WYMrH(BTR$e7z7TR0Y!!tC{&}Sfn8MFt8orrz+ zx>Wr~fLk9YTABI|8xtYj>r=9aEMf8mHcm9f~a|BZkD?F16`uLf|7-$R(FJzQWUda8Dwq6!=@cQo@0xbq+e zsKg!7Kea^_&>BuzxUc%pxF)>kY|rT(WlH&Qkh*#*VczmZE&xRULf`radtA<}rTq@3 zH3vmnE0h4g8#2W~YOfF_S3r{=D+{-s{|Tx60C0#Nu(C{$CPW;-*Z&sf{CDQ;|Ha3((LEH9E4v0&1VUMLOnZAyZ{yfy zH9r3xh4jRxlu@(7&MmvXW`|ChWmg2ugJgc^kf$v>(-tH{t@%%4D;QoSbqz$dtL^Y~ zj4i!fL?Q?1i?ChD_BdzRSqh+HWE0=_xen{xC%y@v0q|6_Kxuq>mMbF171lm4Bdpl zp$BR|@)ycU-k&y)N@K+9E=u(zUbK!X^%XA9aHQgetK45j6YofS@-YrmG+Z$+kweeV z0dV{An(}Z50hQZ12Q8W{9E4{!HBGlpScFRc0XOLk33O_Q%ufnv&vdJ=;g~-k-pq;Fumfp?2me@GwK&|5jw2$;CFL4AAx}Xx8GtxUUG;z<^ z(cP(|(+Hf}Ux?qh5ueVW4Xjd>mQ=vzToGF5uPiXDFxZ*yoXtPzMCU95Pd+Yc%=yPp z&wrku|14@@8V#C-#cQ@L>VxJ46Q!i9aupcvc61P!(N7Z#bG+M|m$rXf0<{v1l1lpM zbLLKIFICtnF>JTZi&rh*th>&wjuwid53Ud>I}%g>x#qa8-euVp3#z#PMcSK&C7s8A zzfLnP(=x4QWoEfmu9FK?mbR&xnYn-q8s#nuP<~ zR#E!g7L=lbhPQxQZ~T)$y&%@Yp7|kN!fr)pL3dj~-^INnF-FzuZg$w(m6q|7L{v8i zZsWORy%&IoxP`|v&a&=#?$2U6*h}cB#*!Tp!7$z z+$vnY!8H`HN(1p7aVIjY#t$!UO}C}AgW*f0Jb#p=4G7zbl(q_YO>)awvo8^8?JyYy z$vG++Fq^U7?~!g)Y_PTst()f_U8lCExCWTUV5Fg#y`Q%wF-#iLof5;4+1BRC@iY(U zny&3OyT{Y|8WH+rcF-^syg`&3hQ~8IRuewk*eS5D2zmx{La!uAfU|d9yWMlOdC5W8 zbExXbt=kWJokWW54r~IT`6b^vcf@RIn;p7Y?~X_1EmQ2>{lYJ?+^9^he%F-`z+#;@ zI5kQq9FER)9+?AQKF_k{Q1K}&Ash)hDnXk1WlGL!BQsS)_>s_eW0UHo18WD2EUQyiG30AANR-_vCJ@i)%zU|A69zxrTWe;!_`S$!1lhvTgG zjjpUBOYtD7T1dWp zskW9)!SUTFn(twE4oIIYnZU#YMi1&*EW?|bP^V6Md$~3nJv6E?T~g5Qqnkb>^ZT*&_G5K!xGe`Ei^qpwHfE8 z=azq_iqQbJk^Ws5RfZ%8_?3AaGY8lNeX63pFXLLpZa@}}o%h*Q(_h$Pi32yqmT@zZY-32u?J83U^(lI7UaFK}FKG7atfguTV z)qh~T)RqfsRnwP(*vf1DWc%I(EiA+Y#%@N0Yqp+@V4PHbt}oPc7CMn*RbCneR_Ze&`0WW+EHJt&<@@K_S?7jF-CY;kPs87 z97vKUO8x+12yWv`zm;qL1w$PHM#8g&X?GLZ#Sf3}V0imNa}InB9{bVo?A+7O&T!dq9e==$`re1B zg{^aKaW@#EsNw;cNF{~f^M%sZp0!N?X49kVEN-afv_*ZIjB3CVWA|F@Ho&G8HA0LO02+3cXno`cJ`$~OazKS{9 zvz6Gt*$bUzQ;tDCrTk(w%6ueW@)%=$+N&Va9tPx09%OsnKd&oJ!M(T1h1oO?qT@$M z$)>P^_%kbVKC^%Rh+?90j;PvUkb^h0T%cs3itTMKyeG}M>XD>(Jah_M+f&XU7#XN| za1{+tM(o$Ss+&EI8dk$(Wig%cGBP}@@YkN&N1e4A2s-mWh23B%%igr2^>N=p3F{DK==y#q2JFE|wa7@O-##gLHS3oZtC z;)1HozZ5%Nt7?C1VjX^3dd{5m?LUPD&p+BAHT~TU#vWQL)-%U69|XoLEt$BsE|oH_ zbQY=62SknY#ia{Y71@?aar}NRu1uU6zC$0UhsyqQaAm24x>=}h#wExLr^~+rtXjH% zN%kg}Ss95Yh^MSGZ5ml(MwX^jNeB_PwUpPlo(<~12klztSe)^g$lrleg5L@IP~wN~ zG>>(S8vkX+k~WoA`bG-a@l$PQs*jFV!;dD4`pn=Q5&3rDl(KgEyR8;yV;H7Fj<~#X# z{+Prx+&_^vfn0T^qKQ=J9qPtd3DZBYGsWeh|2wv_92rF%|0RD?Afx$Ta37vc<)1hV znW1H6Q{dk%#dBJ4&KfeRnV>vWKS_G%d=ppzzK=c2VHa_aP4cf4Z7h3X(&0CY6vocK zAHk?2p@Z8Oacj&0ipW}L4+Jb&mf+NthrwK(YUUFZNf!-&uDsN{Lh8D3Kb$QBcKbK1 zSW5oOJ+I@~Yv@=8H@Mqf-5i)w8wNII!1U_Org5v#Tl&pQ{tYgx#T~bA3fz zAY}-E*Tr*o*J)Sqnm;9v1)Hp6# zzLw{Fl2yi!PjCUU(cyT1Disu)e+Q<2Z>y+pIs^0#UNL<-kSXhMaAl;M7npMl+ElijwY7oo zbq!)m2%$!?ETEp_qibvT4tkL4d2X+Rca#Zduxn8?^G)3vwyv5@2{p%(!cI{+@j@WW ze9LiLy}w@^^r#MydHN}*V(LaeOfoK8o;gRO+*_%tl(>?j9Y%cW>s`}581>O>T)e!r z*vfg#mPB< zU*&_5RQTAnkk&MTAf(>yAC{A ziqXX9?=ZUM4R_n)0M2sFh9=ZQj2cUo!yMcXju7P><`d1(Tk(DaXYSt> zF#^R`+JK~tLey*ykd^J5@+f#6eC#CvHk0IIRjGSD%s=wk3_D1G!$~h68Pm3;si_$) z+Gxve zn-T@z9`Bd6%a$H$C?GlS>Z(xJXtrdF4c9;>eHJP| zac!X;0tfP~;H_8Z%_NdsVz1Hch&ScVpcyQNtjLlTr zXK5uLn?p8(@l3^BnpU36cbs7{#!Y>fQFViKaU|xp%_a_wPP>WdXyj>HfpZ>IR)Mey zjcoJfJ(veL4oQNL&)2H78fkeSxl#@^Ebm=IX1s!L*Y@r?s}oN~$~O@Qj!*FUv)9#% z(JaRJ`bGyNcGz(-{dwO{lkdyCBHN%^L&Lsgv5b6Sd&-hPE4pdj|Fsl}_bF|kFg!49 z=0R%(VC@8i5N2I+irt#_8*72Wj86{SCc8K`GOou?6Rx% zh+9obPGd@o?>C2WS}Z)O;y;*GRROl4&9;(LtGBrSeOE_RQt8rCn} z_h8lmC=O)3o6w*4-)pSqMbHydAErK)!&gn0bgnN+9xonwyNo@gbK;0EeDWU-9*te0 zPgF0HM4{8E-8(|3&&$k`PbS2@r|xy*|EJ*IR|QV!*Us|>_ttDxlUg;4Q3=|nQ?3`o zWaf|Z6-h4d9-v!BRNJnOvg)o@nvSMU6=O0L2<@4f_D=spNbv`QkrU;PKwsnN|7x?n zZP8yU7W)djE^PZL1^Qa%IDY|g9 ze;&kdP-x(Nv#s2J@1qmnt^`(EapHfI5-9+A3^u#ClyhN^V^(D%yApLFFAISNapM>E z>NpZLQDC%W-CPN)%)I$q1Anxuw1W4`zm9t;X0JBuopCD$*j47evyJm{^Y;*7xt;lo zSGe9Ka@SSzg+Knk>{b5<|Mv@I7}&A?pN#KnWT*M=bLP|8VeO+1XZ8v$@8v(?eP~`V zPtJqQ(8yJcLxow?@`3ezQWur(%Ibh08aqtn%Wat#{K7=U__HG6p1Aiv;!-hU7Pzo? ziR<7}Fis7tkkn`_S(e6s#vbqpRNBBA9J6F^or1^{>Dp`b)#c!JNbN|&M~uO8ek|56 zl}EkLJm?%RiIZ^1uWbk+$~qB}nL*l;!Oeh}UcK9_cK{x~K_H_Lyo!OKe$Qkt{wxNN z&a`)~?seV<))MZE zf9?3dRnqT_8(fN6x8w`}!04xCo22Au`y9#FlmSr#nSyFh4G%7xI(1Jm&s&sR3aZa_ z?b2!wWfI|Gif#Wh_93F#ca_2?Ve~&-yK@dzH~WR2@Ug2aG6L6YG&)RzJYbx9Q$U%vWQc(XZM{Lb>?ngjKnvYb0p)ppHq)ZoaBwMDm5C=|4AJ*bAfGxgM` z=N=h}e_Q8UgbiU2Arum_q!V!~^FuGT*>kO^8X;!$HA{MGTssI?%UoxNNTz2A5XLP1 z_%SGla|2N`slDgmPtzsoq>+DT_Wtd}^!+)i{1^(}wkgdQmtY2y#!t8nc&rAg5X~Q< z1cfC-6#Ok7({LsL0AWF zeQPEImwli27kJTLVF_49;i_VI9>V{KB_m0v;<$y>L(^9ZGR8oS1Dn-RPhwJ~`DSor zo9l?JEJq6FP~@<6!{IJsNv-wD)18xPju>Y^1ob?<_Rc9yL^0hskZ-I!YtO@kBePq` zoBWOI-u|cHbtP`Tht)(jn@5=P(toYZa%(}Wy4(EqrgsBIHrU5C0wq?!y~+O+ZkJV- z>hbgY42xrXl>@it*vV`VngzXnu8299G#6gmpyGgVDb-&xzQNA*mVq4I4zjC<%RhJS zDq_+m#v%xTXp~L1nj}f-)($!a^um`id^zkiyl1U`&2Oh#BJX)Va-~Ao&rvXTdjg{L zDJ#|nQ{gFEku^;PST zQ-HUkU!xhAY25o?arylhIH|P8G?#(kmr9`J>wwQb>80LG0ot~re7`!*X!{s)CA(xZ zn@xH9X$M(?`ZD3o9yM4d!RytEp3eN#VT`|U)8C7g0Hw;yq=e^VatQ@uYJYe#nJYB$ zNZ&m-%lj$i$<^?L3_|_n#Pr7|^cRA!zzp6naV**SKqWphIz(xG0}a*2{Oqv_=y`sD zyD8|hOhaE{K@xBvsZzsA#B`QX93UA{e--Mp2#a-BKc&@f;^v?g4lj0O`OqU~iUXTx+SHU7_co^Sc_q?XL9gg}^{JgP0+k?Dj zLc;W5-+=<)pYORUv2CL*D4lM&mbpQ%>zJgkQvZ{O1S2JoZ#K23+x%u_;cNMGJNl;n z-HVN|164FUuNX4TK)U{3I zfR*XO*mnR%YalZj{d}PFFG9Bxb+1J`d}8M$QbIJX+3n6X!|Wu8F|sx#8O4mU-O!vt zfq-}0)P=DyaZg-2m`fOm^y~m$XWR2`M+L47i@qdhglwU|# z8_M?FE1aJta(dlBLTVZj>=#YkI-|%0iM8t1PSnOvf+;pY5}a@Q{Ee!2+7#rc%2~X; z_U`vDi}3F&{2YI+GX#U*57iy9YJI)YCkj1dQb;r`@c9J%;8D7&B^h79GcTj`-lucV z#d2H8prX53zSdnD8>Ko~cKdf-I%L^{NWO(91sKMb7JSOG{JAR#9Mcn&G*Mm3FKWl~ z={lbE;X5|5e7|}qQo+3+^v^W6w^cr`UhdRv9r={v6Oqrkw)X7jcwok#^8Qv}!1Z+9 z>pW!IzLM#hx7ss^Jg;$Ldcd`1DHCW|R*47HXU8c6Eg{#`W}1F*=b zqMZ?PLV%j|+kyM82XWm%&1oO}bp6<|^wVhOq+bZNkNK$RD}>cpJ+5kqDEs2WUPFS; z`Q1R3YHK_J*k@t#{m>8m7gwH5dGdXMA6sa@dzXhR+g(jwFnNy1juS4ym32ubZ?#-^ z61#AFNWW;F4HFId7{l~={$9seapwFe2I1_SVR z8wMx62pp1GG$!dVqUE;`?)O8F(PlQu4u}`)S2I>~@j6gRpm}6}4L&n(uz#XKq#n0` z=Wq~bZ&ijC_epl$NH9H~$vr7tH3F6-lV+(H~`J@snvUvtq2GtkO5 zz?E%!Xa~TihN}cANm58X&N=u)=ojfo$maMnI0>L-Y<`4MuOGqQZm~qT=6DHi74r4G zIk%J<2aax|pn32o*#5$30L*i1Y`qvb`!(mu_5+K6x^WM_6y;KR_$5K(U1GdR&MHAp z^i5Lf#D91pTE8rqBn{&P6|*f=YPhSqe8FJJpf51`Z~X2_yL0uKw)1Q_CF z`d7YwG6q%X2*6JZyq6^PjUW4%p*KfjnprN$AR;#s80rnQ#OFFBK07F+OFLpO-}Hq@ zvWMzoY09f8B;W4e(+?BpztZt?;uo!qppCt(J`fn{WNq~3@-Zo$)>wa6lK4z|gLIks z%s@BD8K9eDYt&mFy)2Hb?o*ztwzJLKVLf(ggGL1{S00EOvTJ_ic0pKcCSZb__lBy8 z2Jb-B?qmlJS+I*f&C{lkzkMM_14&+_ZS^!~2Bf3{?` z!`4^0LT8&9gFOK@*jxvWr=HlDNF!FU9y)(0x=?HK@VUU2+!lwOCZ?V;^xLtc#ro`) zZEdaF`@oTO9_Z-{XHK^E@@&FB(zWH>X4-0?BYfn`_k!}3r;qs%khVeOszaAxJKR(o zJSwOeb21)cReN2-vfR8xN)L>Vyoj#i8W~J^F!2txxWu{BFVB__P=RD$jIK^p-P!({ z=dQ7E2t7H4zziJf#Esz!+~G3iKy{$jzBv&P(C_Qd*Xz_%e0QQo;_6m46(B6{YQ4d2 zV-bLHwFE;WVSp~;a;F%1EszaR2y^Kc9yp*f93>358(&1vhk2p;+MN$Yv1 z=>t8NTA%kAUr#>+W7FoUzM1?s;?t6HQhDHGGVfg*C{b|@pKsGPIkS1}4lWY?2O&=`p*ftzGWB zAan+Wiq49mX069Z!8C45R{w#Pr0YDBFGK-hQ-j#}&N;9}6+ri}D=d3Q?erGs` z65m2mTv2cChJ4|bHaVp*A)%?$sL9UJ5vVB<5aKOU}x(y*8)yqHMtjJ5{vCT_ib=a^G;f zYZloA?zRO?U)w(=_ZBuiiZF>2;1&PatuaflcM#<79 z8dtFx`y>rfy&0$@Ufs8k0PXSVrMS4Y^ zkv=^npNGgs=e}J>-PY8achgSTivE8U$;|(pUp!X~0I8ohZ~l*l=j13W97uL#N^^C`c1C z`s07#I)G|iE~xnCOm^9$<1}@f$Zl`op%mVb?KYciZJdvK|68U5ru2W4-29Z?{Qvzo zIF7xMQ#7wsnLIWox(*GKIu(9H>PPJT?3ZYQJMN#|fFcya{{{F>8jC>m7H-m;xxi0U(`P{!`m$ldMxcOTU2;EtrOCO_r z3zOx3$@=6IF1t>XtkLCJ4oxk!%wux-OwePvEkLA1f{S5-{CNZBqF=bu3d!x3P1`|e zL$U-$^td*2g70%`{zKOW8!@p+ASLi>jFHl!*g_U^X0Eo9We6c~t286|1GfTu zk|cc}&JybZ*+xTv(kle_RcxPON2~2GfwUu=!-N+ z&|PQ7n+qXbv{~|wO{W)q61Ex>TY=d&`pKi1oj#@W&Rc$%-qIje)lFRi3P2pmS@Cn~ z?f@JVdJ5rkiTZRg6=XTv(mNVctX-TX&*-}XZM;gP&$W8e8jJbWcXBZ6tzfd*&Ub2J z>c?0|V*PCvEv2yd6}R~q^U?_xSK3lS_q)GwYBbuTJSP|$zc*`ov0IrKyrheDsIplqVau1&N)YNY-smC~13-g!aU65Ydb%gQ)zTjD?O z#!i{AOq+F&w>IIhP^?hH#{*PrgOpsY{0I5(=#U?zup0HxaVuoBl0`;8H&nR_$+4vo zl^2bR_9E?qw<1(?f5oUS3P{;M^yY>ddi}H~*VK z0h@5mF^@*uXwD|@RhY(i)W#uKh>KCC64rc-aIT|EXqpO|rj%7C+> z8k+`J{uE(+?zIc2WJK;7EI0(^oN>KgT4+8cjdPEoz)gGAn_V?RL7!!y{}&1^9B6}>#5EPeQ&bnvb&vu`{;rS@kGf2Rb0b3DXL4Uv2qJzM>s z0+7EYkj`>SsPQHmFljq7FZr4guc}Z7`kh|}*d6|~b#$Q-rc7-%{rCG)uTTM!fW1Zu z)(F(K*j1m!0wI6}gmz!QqrhUvM7B_x)q23@2<8o1RKMdwWJ{mh!C3l!P?Il_(OSl}{jm;&V&4jg%CS7|CAsPUIl6uoNsLT|v zXC1z+E;1d%;)bILm(|^+vx~rwNtDmi_Mi}Kwk?$p-LavNfU4#*6~%6s4za665V*w-9L z;~cBq%V{KF?ljy=N?3*Y1J9EYU$B#q+O}p&asbX%T-P7`EW5=!un;rHHS;b6Bq|1I zUv4hQQrkoyGI%F-a)U{v*<}7Y(~U~mdxf_y;LebCU=K$>R+g7>;ONEc+5Jn|z#!yX zpP87b6Y!rxv+WCxIF`?hf{1Le7Ct~2>^NPYzVD+W+VJWZ*1HrM)M>wEl{b7#BK`Xz z+zdT_4m&*wCX>~9^M=<1=2I2fW2Ze5w$bF-tOmtCUxA%Ty%=xLSTcm_<*tWM4^R z3mrTFWC-?Zi&yuUcmy+FRr@&g%w(~Q9#zHpGcCgQql`FUPyRc_K&Nj9Z8c}r|EQGP zAHhlMX8QU_1O4ot^s)?WkCEdH$L2N55Kq!3^XXC5?naTQ zt3WGLZ@>6C&a*oFkXhBrmvp*-;z1cb+73i;1#sZYJJV&v6vZT-J4wP zUDaf9{NE%W2gCftlkbW+<`J&@ku3u^sA7$J9DoL#Oz|B??NqyXJeWvDB7f)UR6RL#9Wqo45L z>wI_BQ=2GNzBVyE;91$kmpRUOJ8|-Gc^`;7SoueVE?9YllQn!(|C3$9gX%!nK?d`E z&NDq(8=pdTwkccK^HJLT%LJ~G!;J!0=&EGPx-U;pY_LAyD6hDx@+&`<9*w^Kx&OM) ziF`p$4dR_!Oweb6p!!~kwVvCIQF9}>Zg1I__ZWQKf4MMYj(wf7w zdrzB7sH^mPGfJ^uM6(bt4r#_RDDfaa=gz#+?#W1Ha76yfXeO+Jd8nf-l45IY5o-RU z2J}RHuW)^-nRl`ojO`Itqv)$OOrF`HKh-0t44o6At7t8Hp%RDRjlU#pp7NE_6Z3;B zG(Q-gW*4@QEbmvU*M?NxTj7&8hUQVRn(dd&kgb$@uWj@8x~McvI5vwIJ)r-4b@fA} zHrfZyrW)s+JBitKhV_*m889F#$*jp5Q@WJg1OfS@BumVZqYw4XL}LYQcM-QI*#{>Y z$2_VC`L&XYr1x8D=pkv||0yUjoLOFV3M#NHGcnv}c5uqcFElD+2SOnj;i&J5k70s@2=i`M-m%n{2OneYtTxr9X)}hh`2(;2k3V zePnlP#({<-#m?U^Zr1&?6(352e36mtT9`-tT(=RgDfMw0Nmb*g`s#Mo3w&6V;_BEG zDSwu#>gR2jdmx5ZS%N&3e{Sf=2h}KQKO41(-y=^^`vA=xqM{n--?l%0`>_|CLmh5E z&JT-}`a9FmQfK^<6Jkp96yHz7bara{p0!acFo8__Y-!hK+m4-lWg&%Ne8IG<9aW6l zty`-e^Nbrw(uwX0-L~>{I?~fh`)5InN4rwe1ykStBoxKxmLLh}I{`n+*wPswS?HO? zPFL62W`FO49n#dM;{|!lT?lw`(bLT=9(W`e0is$wP}UTK-#>aW5@!M*C(WVz`U|_< zQI*mw5n#z=0#5Q=y`aURNvf}GV9nNfXGERHMfxC2?VJ>4eo(A-GdTMF97wQjv=+*zuAKO$J=DX-pvEe zE91rbZP-_D>wA22t`+KFgmONm``gM=bVAp#^G78fX6v{kCa9EguneOQ&A9a1o?; zIiK5%Jzr3)eNKjUh1AIxp#UCC(f-JmUQYuG73oAyxRK3hDRs2{pHS7pK$-;lCv-?T zp5k^TBe0t_njN560L$|QGrjP@G(!JlzPD`^55yz2iS1_?y~}zQ$GJzo7GgTFGhkIy z74_V^|6ZJ63{HA>od9h$t+3Fr^VXcu=QGxU@DRQ`FAHW zst{@Ie7&j%H+}kaj1we41h}@f$YbF1_m6W}ea(?&r$}`AABXh7f`qdM8}Wy3Q2FC) zuQ)P^>bJJFZp~+!uGQtIQ4av3g*p;q{7#O>Sb(;oFVKfEoX=bIH{UaJzSClgp*6{% zlPCHav|?Dq?6&y(*B}El+!{Tq#WWgmTCnf=uxT;IyQ*=RpW_6B?rb8;S0*VhRa-Ig zuMf4obsq?rn$#WPyuTm<`S*{*t zs9eRpmQ&uX*mI{7a`EW(<+IbCkDS=Tgz-668>`~uzy`qspRW0D&68EJ3^zC1iu%OJT_$g(rk+?@ElIs&rOqm1 zxL3X9_!O3a5enXKI-c0DbV&aCPf|0i9Z3lHGNfIoN>K@>p>cVmKuO?}-6u3h4JVvksv!h*y@mky&SXn^52996^{v19L zM;+26yjIm>%1DirvWF%Q9o()|b0f#>W-4`mipeOq;Uw%>#zyLYtZ6` zbmD)FuNy#y3new(a;@pb@GaF|R`(-(Twzp0 z<3mAyWg_Im=>D^X*NaN-{p*;8cg%`^{MSKB1>3>?!gkiE;mFrlTUIEhK37RC`2a_( zaJequAu=p7>=%`*4QL=Wa{iy+0kWyCB?6t0f}Mq7mfK${H;`mVqC#2#!`|RpI*7-z zy_Grt*Vb@IRuuD|8s!?f>r%rq#(x9KV-&-_re4Q&RF^Qwh_(2kpW4 zhV+T?M-5OWF2`K+Wj61k<%UKU%$FR9Kqlqxlq&GXg1DX9|+Ca zo@7F5n*0Y4*TnnTF!P2z(=RoYj|0igYQXWMwat|gZ&?RR308Fo#B)YnjI@eA#crtt zBXD~rh5fXE$A4eFl4t^BfR=a(Y2xL^L9jn+$1`wnG@XyBqKuv!KzU446~T%PKleUk zWX*i(fJ=+~&Go@2f#+<+ssgGER$sby)mCdx5H>oS9jPR7;G@|qzzF&U@;ynJBKFK0 z=fzHe{206=G6D@h)AM9A8yQ5>v8{DQtY(1>q=;O@Xk=1e^=rIwh=#6E1n5M--^F)+ zIZ!fhc9iz=ALXebBcpmNR?TX$L&IqPtq;9H`wh~v2%)C&k;LjJGdeXpLB^yFRz4EL z{yB{=?Z=s#|FWh$ru8P1Ov4J1bI3JZ$!G(|41zdycl<|keI18WU;P&F{^(x> zWz*pikQsSZY=0ccmN|> zJ#3^)?F5q0j%aLo0N|EXkwOw_x%4M;))LtU-kQg&)@(ux*o06FDqHN3eI?UMq{XMT z1?r2g+-y?DgVfPgl9K-8;mc-BJvt%8&pT_~gNZUt&{w;tY*@_!_!{O(z5ay5d(5~d zjRLnxYTk$q#idRqUwMv06O6_03JpnqAB0&Bbd4L@YZ^%c)h9X1vM@McIv*mD{6ewD zY1kc~QiXEeL`gM!Z32yv6aOiE{jRpwM-M0PDkwYmxuXshxldljGuCuOpo>=wh;uZ; zEp(^XJf-O5`r)Fpd~lrRyyk7mmu&9U4t8;9p|SG?KSnXumT~bj*fvRJ{iXdHnbnIm zoXU{f7T9gJ$0z+*+zz+ASTO(ejX%FN2;E;r|Fg^=dds7)J3-U}tj+Q~ZeV2zI=!b^ z(}zm~g36da^n;KJj&XWV`=$`M)kSC{Jj`?=mP0`NQ)e*@Seq~9$qkw2SHS~Rqvs^J+ zeYE#uA01ln&|Pd7uP#LUda&bs-MkNc2%!1OF6ZaQXQ2p}pp`pCF$3$vF}m)T3^7Go>(@1*0RfGqSr_xm6C%K=Ek8ZDACX${4h-sR7aPX ztJAV`!TVJ8g?Z(9`t4qw+REl6wC_}7GWX4`Q&7ZvwwXFfro#O+} zU>vaCcgU*A#~IsF*x}CPz15p<`LzkcOe39;bUU!p2%oek|_)Sc)TQGwEUWf1=SovcODJi9Qp&n8vvgp2w>l zT!R6R$AszVXpi&3IZo32LY^Bb_;6I_{83fyYNk)orx5#ztoT2z#26_sbWti%NAuAW5dgP5)K>4259Ir=nktd8O^}_GgcipHXk_Cqn|(%{GcGk z#|iSo*-kPx%Eq7}J2CN7y_bwLzq3Ijy0sqQA7HpA{n}9N7W+=Emyt%5`NSmY zf}*$hBl;JF>gqC7vdB)*5raYAX!;B%_o6T0fWnBj;a_ZdB`5d%rx164le=zGgBsd_ zhPS@dbJ%}Sv{t-IJfp`@)UsVv7BHjxJL*?q1mK(g-b=P^YY|KSQ~2a$eelt9GpISI z6085D?{|(QXO2id>fOU=qAoeBo_fBF&HoN*iJ`kCj$K|E`m?YFjMXTCzTX?_HZMp} z`zaB)tFlNe&1n zwglbTzWCF^HzN&@B)1H_GsQKs(950esE0aln48jVlKfIt!AT9wtWC1N{lA&c#(oyO z;?QKHUuRjOKIK&$#n!WXtfNmxmIP$4K8lcWA$-n!FNUHw(QFVLRB~s_`+a`Y#Vn42{<^(!X z52dx(ME-)zYF~(rSRu&!I zIt|rc>udX3Uh;Gk_3Ff1jFoxEbXH8chgKXxaRjP3jHtJ$E}^+!2J z4*KTjZ|kwie&1#dk|Rfc}%>4;%#r?zA+zq4&!Jq-r7R2fsThfyyd z$_$-)3{nGvC<&5l8l` z^fRa0t^XL6RnfZ~J*$zU2I+w@Y3qG;E2Jp&-!8i+F%DH+y->3HJ4TNTR_PT!hq$f6 zwr}L$YAAUoZToy_=DVS>|1}cYgUhK}b+N5@ZpD$&Xrt(39-aAI5XEid+B#rmZUAPo zD5q=ZH+MwEKFK|quQbHT@26#Dp``~P$Ioq|>9Nkh$~3`ijUkRL@11Ugsii3|)?cP*U}w-w#pTXD9)BaF`nU!JrK#$cnXc)!`#LYyC;VmwewYD} zxbm8z^``dQx4AA+y+Qea74#Ij*%slUwJl-XXYytY9c(Hj#0WgAH$331QrbAmkh*@3 z3=1biOlPkYutP7TfP_mKy$jyJxu}bFIW6-{r71%JfNAtEsUF(6?M!JJ3(k?awov>& z0$j1by9w_Bna&Vv&<*;@F3;yTh~^#iaX0vsS2?^p>p}_fWnR_*5DNDiWL5)JrxdaN z>jfjb#dx;c%hFFC!|@y9_rlPZEi7TDiixqD_GIUO*(DUF8et&f0lmMUev;#%*j=DS z$rkn_)rHr%lR&Ln;+k3HuVE$pU7SYR*n9lvRKovT3v024zK7NNqNpFjHilr$& z5*9V~CsozFuaAaGX4YiHy-Kg8#nAaMlYUKo2bF8%i!EekL+V}3r2t#6h|Ldq?mPG}@n6*S1AE0u(se0^KyabWNd3hC|Fr*VGBEW#@B0H!4Q z!=$O94)D8~Rqsz)P6 z0J5^6xy|k5F38-^@jf~1mg17}A+yRkkGJXn7zRn(gKlne$6MUa>AlBP4m?X`q~=lJ zSF>LIiuo+!bHq+R9`&$FTiTM7*pnFVd$jnd=7og^J2;h%%8IypsKo#1>l)p>Qo#`| z??*Tt%z|j#bb8{5^2Bul%n`*0jS1;hOH%~8{P{b)z=KR(%_U`}D6J2B&aR7jsG3AI znWZE_nNoX(|S*=*3H#tO5GX^%I+^*?c9TIG1tLhvvTC6RrFnMz1w@WglQuv zCLx^KM7f9O`$!SkDU%D@^0Iw@F%&*}dJKT%0qQDox#q`{lj;~tDK2j?@JoHf!$&?a zILy_YRUUzdD>L+TrDB#X5L>mus9DKf};?mvY^t7=!)TF6LAQ<|Qe;6tF380=Kt{x8Db zJ)Y@4{{PqUx=M$u1ByxsbrG%{D8G4S+iZ=SD(-C`}_C%M>n@y>Soyc{eHe4&&T8b_)iHeuVq4p)1S6k zsmH6~4&VKMN6mYznwptc=l%eOpx*}URdhD&_BgY_8jyehn+VXGkIW5vRV$SO{pObe z$xd{k0$RQ1Jtsfn&tavXkm{))N>-<}u;O_zK$djm~N3=v*iow^~?TPPSLoNo?pP#q278K11h$+t@XzfPi z%d(nlFMhXbLvt{5L)B}Z{QMt(5rltcEx9K*f|>%?Q%cqw^f8y5q~j62 z(Dm;*&zifY-29bdfHd|C5cK~OmHsbT>Hqan@6Sq?8^^w8^x*vSRE+Y~upi*+b2P3%tSk2d1qYajjRztjjDarL;a^|6BAK?-v=j# z!D%Pj&R#G^zSwpr<8Aheg<}m=+J0@_#TId`RKiw-#7w2uFVibm{Z^7IpLS`S1Y3W0K0VPtl*&2Mpz^Ae_> zHy?%{M>Rxd>e^b&ScdoLn7m-o51+29k2_uYYQQ(?Rc*9UuXYfy<0QroN;v+X2kG--dSqEWl z=F~Oxx?r$!pYfDwn|T8W-78sZb-G3OQ%ECNFLd~> z3(J0aQ+vl{vWV;FBWG3W?=3$3n^*-fDhY1}uT(vW^q{~SSp-%4O-Hke^L^k($*hnK z#kG`6NlvLei5A{a#FTRifHNNUWN|X|Z%u?r5?I^IOnU=8g&%}$Sc3TpB%kWmHcWZE z-&PQN*hDoPw4JSc!fNs5y7(!-C8+?zi-?P-S5z>!l^~+`x#^u}Bzxd#f4w)u17{Xm z4mi96eE3MywW(4aZn^V+N*D6gAs{E|^FXTkXZNU-4sYo(p|iMwb{5@Joq0(;IIKci z-OTfq7ai5+9qFT%tmH#qHe^i}&D|M%oxu%SfkfQ@ll3-E?P>iYWj23AC}aA2@RIL` zokdDP0C;8R$Z^DVX65TIbpo(J>nF1x2bgt6Uk;7eW7*vibJVXHJ`AjsvH$Bp*K zxZB}^r1N}z&=t>UKRdQnvg7fBwTR205f)f}2IJ!zx3~99*AW#gzxA%|QF}FGEve?y zS;R|=t_f-}V~z{pArmna5EYU;5I@TW!jOM%_hAyqsRN9jLL!0p??G;vpS^Bj#2fD= zr7XF#3{pOtlwRQiZ^Q8N<(d8Uwv?M=86eBY0;Wxd@=CT5zO?i4oPe{vIuWEIG zCd?x4i`aJ@t8tmPXfbc*b>F##*5G%QoB+mm#eRZZ$Ww^iTZXs1d*ekqhlJGb+dH)P zDd$P9bM?i`zxCLR%UF72&ikS<%7!Ass-^$4+Pzlyn!KS%rlsLm@M!LSxhEUND~Qyq z1K=dOm;RzL>?Wr9P_VY*tXA@rHBha>YRKlsCpZuJ9pkwnQfV%3#V2m3MX||28$Dzg zlJ(fkzUGh~S`&*>So(-Wf?SAIH$*WlpL9V8_~x;)e!g)d$ZTA1ggr!oa9}^-q=|3l zvPV>{i=2;(P2wV+&_fWTwjC`4iIJKSD$4W1IgT;U8#$v6DllosOAB0H$8`j6~oMx9R(R*UP zQ{Zg3v^a6YXy=wp)%Q5LxG29_r#HViJf|+Jmc3xB%MO$Jw_0ZXyjvbR`qW$qZ>@tn z`cm&AW;2ZPK~;w;`a5XFLMc?rd+dxIzl`=AmKM{YVD~=?FaD8ZMstFpZK$x!;GOl% ztUfBH9b!o2`TY?FhLQLvj>oZrJy)|kt{b$|1F0$g@2_=!6cnncScirIJjsQ|qE$}{*5>*FSHDNqfioJC8eb95fo@^A zWh9p@FgFIrWon#{Z}_ljJ?VwpQEN7muZL+;uvC?w{ipP7y7t>C4ERVJM=)PZ}}$J^w=EE5+CqeCzLDtS^ zGr+v?9+gjrFT8Hj&^*5GK9>@Uq1q2e_hoNHSM||`)X(-Z3@A~&@h79&#txm&Ggqy` zDiw2T2D4VwecM4%O-+BJ196Z3qLGYCIPzihy9cQyVw0$v$;W-Pg^!@w)xgkQrzrg4 zmq;`UE1yQTJqQem9*RvOLPi4v`*nr9g#oP+gJ4H#W)gpfoxARQ1jV8JRAWhD0e&hb z0qZHfd&7CrBU(l^SK7~o;;IzFjgBA1@LOvzHxSo*HBy5nmdo={KhR2|Us>vhBbrkY z2lifX#(Hjjmc*ory&gER(rirnx*>+sijUPT| z_=XF9l-_InLgdTQzjXT{*X29!l<_m1KGyTbgs2u9YcbWWX_4(1^PR*VdQM$@F|h$X6x?)&E&6g3H~?#sY_?pVT6_B!C2i~ zRZ?&!w!b=i+*=3MCnLBHMIZWqBr9X*txfkd3PC3Tr`bq*>$U%s4kkEC5W41z2P4+1K;T_&g}blt z&A*eAM1c%o0}L!n*sr;wwgMLe4naL`4J2jJ)3uWJ7hOJP%_I$|ZVc_J|7m2C_s?)~EflVJcGWS=xB)XhPE#KmH^hK)+|E(QGF-?SYk8;)I5liYZ%)UA*!Kvjgn z&u3~K(Lm2i;q0%0gPQq;n2e?+9b;IH?P6NR){d7OzFhrmWMzVhhYzbixjJ0y#5~g5 z${4Si3FGa236=59)bAMw*gUgIjrTc=rMZooynGaC_d%!vXTd&1zRRek!c{28yMb)X zZ3R96$b(>IbPLxmBfXR;kiQ3IQ*)$UC{#(`Sk($%SNc+5z6yf9+0G1ft77{^&6>G7 z)?x~hsbEj{Qy!i5S#Q)UfwhM_AIvuW0Hozx&l|V)KC=1OrpxiDYJHvdwc)C{StRNF z2gk9>GuB}W_2-L8=ns=Z;IJ&K6kev~`zuXTPQ6LB7LNz=@FQHC&#+?-_CA5y)zKAdbXPgIiLx<^+3&a$^w-x=NnT&&L-ee z&W%S@H68<8;Gw~Z3FP0#>+rpHrD_&L&PfZa`(J_zA^1)U&+dhGD!z*voR~zqkGRR6 z8Pym8J*e;`EI)LY)H7ugGjG%fe__f*25(&(0IOn>puYKZPrl6HQcJ_ajg`8?_J5or zNaG%FtFSud6*L2OxUiTep9nc|%N7S*)QBt#h&KDLaleiUUlN z+3=))cHz@bhTX_MbMUp24Wdp!={WZay(avymoz0-t{EGI1L#4O$n{X+9IZRsd& zN}0lnK|r|`^;eqeBdyvX0|+Uc!d69W5@cX#Q%CwzVgD)F;vYCIyx(hRMkd>ZgrEw6 zW=yOx<+>zxor~Dq;}vUH-x?&xFB#bUa|-%Wh)`QLQt6fhj3PtA=6s!{X@pn1o$j-s zG$i3bB-cx^JpKIYMSZuXp)a&6+A&gB64X3-S_LkCU{v>ms!C~0zoc9qf|(el#*Cay zK-5K?s`dJ)e!AAUN&5jc{uj5ZmPWths=8j!?`)I4#dz7%s<7)=^-E>tE1}v2%O{6V zm5OBV7cs!UGI3Y5{iObNg_mA=7Bv?7oS01R(Kxq=LW=g4bgc#%cnm=dAJRjqk(Mdq zo?f3_%86Y@KeDWKwf=;_gfe1R_t^^aaEL<+SYhu31iuJ zIHsiCzxHkIT{%8F-8dI+rWVw`{;-}%S`*jn5q-Jw??pSR!XH171w<|KFaJ4l>!54p zWUyX+@0ooLFZZ^*%J9wgyEDrnQ1s=~RaM`2`u0^UpYITG^=AEtX%zFiT&+{D``*!6 z%yB2xDbd$AWN|+5ZhBmuMFj+H{B-z$9Tf{uokC(h>i8;|OGP9xc>bTmvR2a;L!`Jb zGX9Kw`qSJ;+`*7MG&;-AqeN^0&O){h9WX#(_+|}I+ zxC7z9i?IF|cj6t+@QoxO;HHj!unSHL?#VYNVB(hRI02peBo970l2o`?ixojK(peRm z-S;=E-&cTEJ50*-MGD<9csR4IGGY4nFt#!g3+gtjH3$Z;W_ey zLg&qB*)Y?ZZFA~|iBm>)ZAO+Cv&Zk}(p*V*UXtBP?2DB&-$CWf?{NuvHf{T12qXvv z7{q0<>1cUY%AXO>wdS@m?g7P-bIJsiq4PUGFk3M^9*OWRqlJF$5dbV1*FFM8YP&g` z_q$c&{Xu#U+peUuo5;@lU%d$}tQ`8bX4o^@<;?cd!izljwL?=+2xoSB{DLw~LGv<{ zKt{$DcL|NVU0 z=g*ej{KH6p>8dT7*-@9D28SQZVxRl~!nUJhKAZ1tv&vp~3 zil5c9g|jagCS9xfiSo+Ym6<4H;KP^sHf`|1cnBrmEBFk+bET9(Jxt0s?HS6LPXN-YC!&2cBcGUY3=-vqES%N{oam z)ZenKEIzkDzT_nvvlmff3RS<7k%tihyjVb z{X|X|$3UJ>qT?<%8RhSWXY^!($M z=_^=iZJS*UU@vSE4A(smB*yATWsK{{@C54DFkayH^xDgF0UjE~wq~w=5G_jcwOp_JoHxD1mc&#%+$e6H0pBsS6-7Qmz~`pp-prCa!`ZoL8Y*2#6B-L&imU%c{7amW}o z2U~sbXVR3N#IYZk-&UQ5%v>@PNSUKQMpCV+DMmfOAuquK98rC8f1Ez@h;0P2)4%<3 z+4;uTzmlHv=@q)u<+h=up;Ox5xU@=W(C0eJxuVZ}r#oXG`gO(y3s$`6;0zi^2Ii|( z$RCAF zX-qpPj6symcjIbZRq}hwox^eyj%!EZYZ)_Dpl)KEZ3!E3HjFQ|Qc%!`XG}Q;iTs2sQ?B@JX-&S+1D6X&H-U8I> ziIe#H$-sMM)OATWBjl#YP(AP){(DpSTs;%mPNJ#{{z>uD4;ZofUh~iyOA=c zg}ly^@N_QXU2p5!dI?@5NV@Uknk^t2=9h>hyc*5<^AE)odUlMD#wC?`2sKTk$AhfS z`XmN&Y0H5)@Ib!Wt=lpwaOc8#ZEp|%B`w^wRGw{`9sVRdO4LX28yoC`H0dqSFtbCP z?&NR#W+5PVSA_@@9YBjfZlRDzw)Epkts#we7a|`7yQp*7-I^T_Vq@Bj^^uoZ{+fn%3(wDyKJz3%&^g#W ztkIjU*~?#y;desE<={@7aiDV{wg_32SpnskAQ;g z*6lkC#iU(}`bNx)U(`fNw&oc{>1X?LBAR6UL{OyBJz}bnwb7_K;50R%LBCX=&`7{2 zLzH{pg$x#tt#Vb+1at8O{wKKt6<0RZ?|^QzZ&jc^kMZSMTHST8uo{Qol&(^7LjwHH zOQ*Y6B(s_Ez0^jQtKnX=trwMVD$eP$#&`@4kqL9V>pWa%KwRy%ml03ZO)5ru{nU0o zi$8E4^}B_hT!?2}D+rBHH*VM{#j&gC-f21yfTD;~tb?Gmvw-VI)CwtNP(6Brj&r`n z`kPAw^g~m?abv5~2vnk;{cb44iCW|gdfh&ow!7o;nr#d;3AtqS*GpO53~OJiLkRs~ z_DS=m`*G+o;;Oz!gk+ry+3)SRVgr|4$~N3GG^04k;K^9ena3V=9o5(+2UMCDeA*4f z=Rc#0ZdN_MIs;IvJoscVYb&vR_{?gfF=@xR6J@Lb+;COAWHwL1M`BPL6`p4tBRu9D zXV4#FNk=W?6}SmlW~XN=RyfwjH@MV)BieL4BzIOZjUNfuDe`|!Ppnl2X8A&bt`u!{ z?zS$;tIFZvZ8h^qh(r+f2`vecYdpub>?uTi$jT93F}Ls11Ks5q-M_eTkv^aZ52=OHkT%bXqp_6&?6z8cTSq@ zgaVXM2|N*&DntJeobgn8P%znd`$mEY6pe4we;hn0B|B zJh!;U(+|ARAE{uK;V`&$e!V>;xeu5-(iRpbD&6N-?}CLF$z|*7h#jkpd@LeqxTiI? zPhb6oGJpwGeX4$3BBAJe8(VNJ)*ofu=hZ+$Na)eUL!q+ao$%xrEH`P-3pOFmn2tM36Aabul6dV=T z=Dz(sWyQa_c2eKOg&{BtpuM<3567Z*Uqi1_Qy?`HkK@RHq@v@(LTg*ZV3Hi?>w5@K zDS$#XDU>2g9zWf>_15k&igox{AW0Q_xH~*|L|n%LO<+fUhHSlq2V3vFX|-JMZrHUz zZc*k`PlxOuv$uuHu!jUHQufP3-wuJf-;6w<1Ym^87?QUzSoq=t8vsA?gzHJQxe}O= z>+@b?&A@1%Dpz!nEDQoFUai^Jr(DkI|CEfFzK!rrU+~ESR6)TA^d<)VR3T>C-yWdj zdQ;CLp$3ayrk@5sgtzom^@1~4W1MnTxUJ+m7cU>adsRuc2S21^Xrch zJ6=Aph9P}}a93>5g*utdTeUD-sOZ5lCvV`Dm}Iuq7OItd7jczlA|bxsu&k0qMDjFg z`?%eaD8U$MokMQg<15ui2MQ^dE5%gb#S4(oEue>rF#qZrzyM+6S2s3=A^Z3?{!e!9 zMI5m?h*~ZpMaHcodAdm;6sQ3$YhT}5q%;LJ%dW&7%vIS0%&qwH^z>H5;^7}0nAj`i zk)s-a3(>$n_;}CLfozRMJQizPcfG_AO|pGCd@gQZ(K=hhF8TKq5rCONiL-g#Vi(Kh z(o#A5yYH!rFKYgAv=ofE11X~d9*&>kx^sw~+n-`oXPY_Of(L4o>~cF&rk>;rq}*8% z5OIe4eaHRB+zj3{o~5pKgG^Suk4`Yb@BIWfJw#fkT-T+L`}8lpSM)|l9ya(o8`#Tf zpwJK>&;=M(Lqp<=I}6H*5414P?Olof>eg0)$#lzm!Jr}ysTh%&3G)&X*`K7KdBBfB zW2Kzgx|dRE?OAt6-AUKGx{*Uoi=eHLj4T_UqYl#pmP9OI{HOZhAnMkX@mr%@;9 ziZ6NBZWOmGsjprFw#*A8v^%jvkQXq;y;`Ue=!XNZw;aLj3v8Ream)2C$M5gxM4^bU zw+dW31+OND%ZEu@ob^vN0gYk>ptF#o_K!tDw~_@?YY5?Iq)m8G^ZT8z`ET(2WW4x5 zT2h{HZ~e^-x8MI!`+4{hEUEWvcg74u4DlmnqW1VDm-d0HHHyuXi-Ag9A)(cOKJ!Kk>StdZeIBWY&*-Isy&D0mRuby{5av+(fnm-A z5Eg%usfMKsSd}N&ym@yekiiQj9MJ0bbh+n}V7{Fyp)a{vwD{M=JE{t2kZBRi;&v*^>BPg?fP#y1P?V%3#=~9BPqO zuBA698qM2WO?0;S$4F5N9uF2o`sE{T4$OOH$y> zdELhcJ{@`cv%Y;{sSfK&a#}uN30NT!Awia?HTiTvz;*XLadbkuf3sRTH@=VSrw2>W zX|lV)(*m1+mSF`-wN6G0P;kLp>tOqiGT9l64=P=pQ)`up}nB9Z+ z?IBSAJMWV0tEA>8)H=~j1$gG{WN)Q~-#Dj%rZ5A8(hIc*N{VxK6UePNpRu0py%}uF z9a=7NJpFyYmXkPGnX#KjZ32X+Id9-O=Yr?S)FOJvxA!b9?K5 zza!{@ze7DLn#}*;R0oQ5muGt0G2#;WMurF5R!hHTjJRl!aw%!Uocw+^{ou6}jp5mp zw;TEx-?am|%XOlXIRh$UY2%5(J%AVC0cH)EnfqAbcD~r&Jfr_ybvX}YDNo@p{<6J+ zjG$YkHwX)=T;5G!|F1Y_e@3~jAj1{3?*X+>$vWTvDY5G$2sC2*%3Bp= zET_^rC6I&rfqeJ>?>yXB-7SyKL3eE4EiILSFj8URKqq*Zz%5X%;ol{=nVo zUu!%B5B#UiDi%a5xP`ONxsHEvkOc@ za4e?%oX|rU^+H*rhKr{ZlByT0*YZ@>GF|hKw8snm8;bPy2>mv=wB1(yAApyhMO>D0 z>*lgNH@H$>XKm|H&%kbGp9c*W~4=FKW}qFp0Y9Tx)=({H+eT<>2|3^n7Ycg(SPr+;3D*1@3secv}^ec;_k5Ewm2kIpv6zJ9m#GQb9C zEW{|%%>hi}dN3Jf`C-k>i0qeJsN*~eCLz%8n)3cwrv|xDdCBxe+PBz%i)GsJKF0$t zIed642*U08g$5lMOR&_rb5?UDULVQ*<(E5#egZu+;>lqhm{YlmF0k)m5nQ1hQS81# z%?s|%=%)+X!G>pkvMfceNUx)5&>2ENH!+EC^&l`nE@DcqtyNSJ-ygqu*uhpVF#FgX z^-+N3sX%1jd6vI>jFM+jl4@D(oA2w&OlPUM*dMI|IRCEWeSRjQWwniU%(49$wiIZpCZP6$A+mF3O%f;i#1MYtBu&_&~AKYJg zJX`c`SXDUn+=}^1F2)J)KTj76i)PY-%r~M6PV>>#+X`RiIWBta^bX3W5S`^E`#Y(; z0~;0li3`Jj@%N^E>U)*M_1m8!idI;yL#HR%jvXe>cz9jG z%?uVDWrRT5D^#VJOnK3dL`&kjH|C%&GvU?;?)bDbx;jh&R_0sXq9=IU&rudk|Jho% zjN+B|lA)jxhrZ0Y^EM#IjTX2M77=3yggR?ZBLOs|7RDRI*~iRY`7?Hp#UCCJcaM19lj-%0Fzit((J!K=gglhS^U>-X|f5{Vwm6s)xf-0GX!s-6-KRJ`Cv zJi@<4R{s<7cf8(cFIC8u_yIfoF9ufDcMhp*X)(FZ`A7+-Z!l_%2p;$Q2_oH`vNuhi z;M;yafpd%1&>sPfctwp@7wk@J2`Q3b$EH8(@^LbTnVnqp+x8o+HU7P_QQKoo5~xLl z{GRkqG|#wIfXT;!_{f>2x+O69q##-8FU^+TbcD^* zSrM32#(3SENzb8XDm(GFY(<VJE&@o%8wRg7IoLanL7}up?>x6~ zzK09&NF5`z$T)pi=21~u`j%?$^6GcsQhFt9X&HXFaFW{=$i*k5w+4F;r?SfjUJHmr zF{LbhC|2aEFL(mLE6F?(!hUExf^idPZejwA11n^9aaZxZKfn093QOstK?5hFn@rMR zr-1=Tzk1iVqU-0~@r!|Tz^(D0(qln)ZY2v~@ngVkt{*;(p2dIS_@#uQsN}L|?7xmW zZc1Ho?P0_Vh+*00oY1)ZJF5+iqRMlom(CaJaH@nHAm-}Oq603Lo&|B;I-!4FCc+fG zobj*zc?^|<+deztr+qFB*-I6aPTOUp@9?$_tzKZ5S@dQVTS);x;td0RTj#OoO_rxY zgSm)XKm^#2ag$zsQ5=Y0v^D0txE{VuKfB5>Nn*vYPey{oo`b-E1c6m-DDqEjX$sA= zJNs4$^--vIFLYO!HqoeB3Y8^)Y$q0$_j|BLRX&>1$bOD1OB))r(C|&34%)QQW_0kR zO?)dB)e9}7$cN6${OFLec0v^2Ih(h8O*^oo;D`RCP$L~14@)Q@7?pkH(>oFl`O#8m z0T=7Qn@)uNv!7GAPTONu1Z;r>`&yAmRME0%lfq9#%|kErh3(BUr}L#@)Ocur$?+#I z;6cvIMC(oKi}z#UM!>&eUp}UJ>L^cg$Q7(tKwS^TSzeT$3iX4oV%LUkS88UK}O7Rkjiy;G=@U~;W!nN=B&E!d)B^E~{lq6FB)U8O# zqt}ifPjT@;a)@7{B(dx?$njpBQNQ==r?H!7K7fnxH|D}B>-~41ZJhFX?HMsOzNnX~ zSkEGE?dRl3G!zLG38p=OPC7^#8MAuV^X(zvH#1%9Z){f6oUU-z-o_;)M3Eiyw!TLtLV@yCDE!u2sAmYaqDw}4t(osdVh@yQ( zDLD}-3+Ea|egn`zCPmJlAnp(Lyo=5|*qnMeT?13V_^y$dJRP4^o`KNt&H@S9dP)>a zBR?gO~do(wLWYqqW79Un?*Cw|Mo?XUF#{yIJ`-FHn9>`f#8WFkX;ttJ!6bk?z&KE?0Q41GUTpa(q1yrobP6zy9@J_N=Gu#FL{P9 zV;a%}LGJ=i2%j-6+5R>>ZqJj-e{r1C+#1)SH`?kKOX3gLJjCmYX{?%L1PcBQyQ`^H z##JRFgPmqZ2Txa*fZ2RA5i)!@+tKfm`wqo)>8wKit1x|FcbNaUUBh`TvIDS^|71OO z&b5E`YP(sTb@<;t6(JqTNW^JeIbx9@9^=yCCGI2Ixe_btRZH|+6}4k`eFrCDPae|W zL&%L)Ji_vFv>zwzXl~F-1%?K{XOUWo?a^%0O!%TuA4(fPsTKa*L5fL@D0F$!+0wFu z_iB9R8$T}MvD1Q;kMf$xI<|~e6OB-LxbXe}lhOHs2Tvn@)|RQ4pK+i{%vn$JP91 zWYNMI&%N~TX3-|FcOxlRflZuKmo4j3Q!gk)U0X29-QI&I_{Mu~%tsgZFihNqu4#q^ zVWHR*VHn7{l3qrQJ6}#!GXNwUY7EPWlmH(C?^TZkT;WF0VdvlUHP?D-psodZqageA z`^Baxuq>?QCZD&o%+Irn@XId*Fmnk({quyx%I_GCf&`(*t`5bw9TFcQ&(UOmj#)!P z_GE(2j{7~}6jR@^C3oiimW~x@X_NOu)7z`Hn2b`=Q+dPv@gM*#T?n_;F3bzVILHVd z)9!@_{ni9_i1h}YqsbG`l)#-6ya6j)TDGcoxiZW&f8Pt$dsucdsEG9C?c;lKVVdy* zJaicxpQy3LfD+`Yu}OLI*Hbg3D7rhP>$S8*#=`3Q3BC$>{%Tu=utUZcAi?*D9mZMFBv&{QG*mu_3!Mg8bQ{H;+0bTrRcw-H8~NWYsOBl0|`} zn0->Cy_-8w;|fu@EBp}V_~aOlk?$Z8Es67y$PwLh1ok`TB!B41mXrwTK zn7?Ukh7Zb1yb3xyldv22>YP=96g9sLe3u;prnk6wD73sQV+)=lU-Vi1n0Jt2ZY^QD zGdIvix712G6`&V04yPLbg)HDgW}h@aipe{!P`@QkeR>;`9}n4iv6nn$>xKh7J|aQ+ z=AK;(QTPIhM%m&R@+vnT`sC5u=q-S4sVp6Sx3QaBtlcf-QpJ!~ZRf+EN;>&n5aM!z zhvsD5uOYiKz-hj-;omw9q!Mf>s@&J_FEAjm!WKQvy&Fc-HfbUoSt1&R(PW&;9NfeKrUdG)ru`ZI=iZJ{zHEHL{^``W;)z`gH zcih7vF3b`Hf+J5eMZYEaW|1l5NT9WorD1%DH=xLl;=Ka4Q?w3B*NQkS^u)Q1zn>K& zhj*VHOfC&WwXd38b-wd7&$g8w05M;fX!G7ig$csA&=Al1T_uG(_ExXWnoPhlb4p|c zPv-T7Q}3K1+(k2c#NIq;yADN9&f{KddGt0sSF=x6n2b-C>A(_iHxmABGMVN1$2fm= zVpt|I7on#+jrGq=D2KyE{sX?trD{E)DM3ZgGLFGIwE70N(^PN*8EK2f_AMV`-cey_ z4s5S-z&l$hC5cO4I?EN(T8@I9dysr{`kI$p-uzqralGm*6@^`)qr?zHByY{u7NU#h zYD&#%2rP!AzpKv|C!pL2!U}obv)CIu4vzKdv4=EHg7^(xWY?6SWt9q#J{n@lp4*c2 z4<>^^Vt>J&_g@4}5i3i-o?ND{^Nl@~RyK5T3g$oVZUa z>jLrg<@xlyEjf%;Z_^Z)o_ho&uo`nZx9nNm+FLJ!Aw2gtbTQV2{iig6_vwE}!QCDM z4{LO-Gu?(akrD)!-Ei_jb_4B?*RSt+gOsN|Szd8*0Z{iZl2Bs{YG}3;y@V&|3a)zi z7}$oDXJj^)-*H<`S=t59bC};^G@Jj6$yKtd}lQmpL*6Y#Z!Keak zFIU6!cmVgM!sr@BL6okiqmR)L@`!rF*ty7;fCRhR8|aX8{R%0=cO>qOxiGz`@-=d$ zh-uxwK)V|aDsv=rByS3>fDOCx=>7vtTpMIVn+3LS*3b7yUrC4J1BcT2Vb=O**WwW# zchUXR=#XPR~o!DmL=yRvg>~mkabQa10z+c!yNm*Xu`H3c{lIV~jB-rAULZ{mHxs-NU zd7fogjOITEQ^)767Lngi7?CyeL(&!SKF(J!RP_2=nR)8osf_e^BpiEb-WaYP^AD<~ zH+nIt-=M7&xR1O|gVbQ$t}mB-e{&3aF7OeeBn9NS-+v@~j)qchIJ@YrW-S7Po#|xR z?)FKh>3&WCv4qgSR!h4pe9)NtjvrKD;*YyoXIDS}095Uj%Uu zgU4#|+W~_opCV8Ot-s|HO!3|~N%SeI#os^VF#|80mT7K%=@NX<<`o^9Mf{DqfS!zZ z+(}HE3|@bCw!DeqyVJfnB(Rn!pB9U5a5F6>`8%Eey@6zOR`-!`wDSRtCtc4UkGq`f zWd327AoLQ6>4?}#{CvuMIBU2Vsr^eQ46`6_~wEjsy`Yj>w2%>>PLs-d#c>Rvfchu3iO9; zHO>O21EXHi0=wIe0@H4GcjhqL@b5MB^LrsFW@`aWA{A`-Ew+xia@8=2q6ie@Zto?Y?byXgwYh^Ci9z znu7Z)x4`1Pi`lX8>6K8_-i39d#zfx<4EXL{!M6DhnYU6IYt}mMg_jx*a5ESxwmFwtiF%u zh{vl@f!Li({sjRQmY0tBJc(UBrU85eJGFxbXC|{lju@;Ozzo9oAs36^g9qL@w@++w z6WFAJO0&DLzh?ZdE*{1zTI=U6Bn6fB&ue6dxTDVVz2`EPIm*OuLe=8Yq*jQ9ejWd_ z)SuymSiHaNHy}34$+@M>b%4!Wlr%Y0X1f|dU=R@DG~t7}PwtgwAfR{l+Z#V?Kf2~u z>0_K_ocXWttcUxr9?1XsbI~7Z{R^fBK52C8{84~$E6Ba&*}p#1%|H7&v1>yfQSV2k zzIVQoiXO?{t<-bP4?*=~(rN$lO{&j{9#KDs^3wo%EoMm7br>`X)I{X|sOn#1f7reC z$BRuPvxD{iSASI1``^|s#kEEZD}h=9_jPQyqUW{hrCd*k<~4dGgX7l;Koxzlq0;6S zdg8mQ-$q!GQWTGtacj^teY*K)<3CRum#T|g8DekJ?!gU{F|*Zcl6rE`Ges8l_+eP4 z{=QYx<%_lEL;iML<|%V1WN$Thi~sEnEfeu$uVAH3$3+GTiknl8&e@dOp!nD@y=azw|)8Rmk>}{k0&=Eqaz~S4-<6#8j40( zOV?(u+#I;eQ;}+UEviovMR9vR+hv@{f2lA>0oXr{<+L$Ev7;qzK7d!Mhlv-$sh=aK z+E67s5@2ZFpt%4L2PH+dSa`@Coy?UYdk*-b*UUZ#rhLB1(ufj)lk~c0{Yk#NyY|bu zV3;)Oqe2h~ajsgjnB-ERlF-2|qF$S2bl@YjZQ)L1LLWhx#9BXYm|=HC=bjar*F*Kc z^D%-n6j`nzDuyH`Al-_(KWi?TJ12lW9Zv3n=yQ|8r1w+ zA#Zg^U+Os9r8@#{OfULvKaIQAetPq<@gyrHEL8SZp6}n&GJlZv_Y2k7siFGS=G+wj z5Su>^w`3;2FMy|$qn6#a{87MXfcz)lsm|EzEijdC}I zkCkBJk>~I?Gu_zDgnL8#4Gqar-riDzi7Sk3_pnP~k}SlE-PcR7Lmeis^Ae^Btpm79 z@p1tu({h<<*tGLEKpEOg9(*rMuDG0aAOV6y^W{ZNv&WWPouBUc*Y|DDhd~io#a%lH zOTIezbJn3H_cMnvE_GYoSV8iN)^7TA$^PrCG(TmQzoKH|I(I&@z|Zi&pP2MA2oglH z*H(_-MBAqV{~!||#i2e%!*4fLBd`r`zidbyrAx&5Fyv+4%{P44tkf}$AXzmKIDaa8 z$3ItD2tyh975XVa&3T+>+g#w6{e{5sd)ooZDNq7Ux3MNU1$(h2u|map}3Ey z;-7zBeCHF!Rj=pyf3*rN%~4uOCRs{FnnDhl-NP+rfE>+lW#6&Z+T_IHF6?9D4gr-s z!n1#HioYi*gh9!A?6gSl?io1!p&J?w@Ixz@@p`?%q~8cDLjg!f@4pXdaaXzBpY9_t zlf8joGXYbemh7z3PHP;uDI!`Lmn+L93W-eL_tMdMZ-z3G_=B1-bZP!{pX;#^i}Y3l z79({>iU?ln^5~-`;^V)#MCI+<0!q)n8wli|!M}>)Qm!eZBN|Qo2PkD)A z4~av5%kGtcq4o0gC0$nB+X91&-o7vLEs`Em;|=+RN5#+rG-6DzdhI;H15Qz|qb6&(fa8&Tj_ zmr(H~Z+b_9=cfIN{&xh*S03=rG}NCTvC^zRH<8aajF!g*>jz`+8izdnJvF(nRymlX zKBeqkadVtsu0S6X3EE*NuI6jC@1{T1gpa z2YQ`veONv>do7$(hUslh2?M8L)SE$HmuMZ)8>?s&Iqto*nB_+ggUSHA(RQL_^AvxF z={r;yt?d=7V1g(t5DQ&2fm^0()A5!7Ugrg((bb zS@p**oNS*g9HE6qd})0JEC-zpc6dH72n-@?r39v!wC?b63@(M=?m3n+U-}O>!(c|y zKl&)@%Bq21&eOaTyh@pjQYR#k=czF5XzRCGpx}V=R&00oDgialNR)Hv_>xFeQ}<;b z@3<^Fl5aFOyaxSYJh9w)%go?RXef{X0F;H&@b}e-eR_BxzC!dZE1LqR4nY-W5bgr2 zMxzgX!Qw+N2`BU*zg*O?LoV9N{@(X@>|*lllTW_2$E<&X4bIL1t$)nAXpROulb7r6 zI3MyQAH)0^3V{SoR0|D{n4zxv3O#%9Fkr;xu!pWl!1Q6kt8$H7{@$KjX1ZwvE}y1o zitAKQ*DM%{fXckDE9RkWPZryAKagzr6S}9aCgZb z_78kMy8i<^_&+5B3$L}X{o2S(rfZ7~pSfrjgiw>BH*DG!^^3B;?=krs23^gtD3nj% z^)0f5{T8bay6kTs4nekB#=+x14TRaOjb-MYX0VKTE7RcHg2G1JYm zf3D*(Ec-=$fJgVfqeHX}erS4yb42kSx^JMO^TbEs0S{z?^d7t)=c?xAa-wzg4;eu| z{chOc($wf-aJ2rB!8#ZYSHI)n>quh#vQ%zg-B_9%N(s$UE)($=$if;-EL<~8*|tl=)4<0wF@ZWx7qUx#=tilRd4m>nm`Jkd(2hubK03!du>ViKCyt*XC!iP z^f@xS%4{ozRmle~G->A3k*t?JA9~nR+K2~MUwNzN`68dt3EVr*&4z971FaQe8c8rW z=7_klU_Ig!gj+$-=ZIgtd^`UY{U4IfJ1*(xUdPnlVchO^93Sz4JZGbf;! zS-CMF7dTK_R%U8yYD#9q38Fa=6_rkA4jeha1cB7BGJ(Vr3FQ3lzQ4bD=!5Zozwi6L zUf1=!lB&|F_0TL;Lh<;bbaOycwnap+EGP>$6EFnz~@JU3Jkkr~-&t_ees zOy%b&j;?*#RVXWvjMv1gxkRFsk6t^aYW%3TSiJ?6_q9a_6_$_ZDR&0tZ*_WeG-QI# zlT)@MmCru+P%uKy@+^lsf-D&+%@X7Wr}~M?831cgH-L2yfxQLa*)QJ_;nf0_-uGQI z+{Utcs*&I0F9J5-;#znD&Sj?c9(XPySW!DO4{MR1=Bydt5saSVuu3Q+pPQQA-3#qk z7}BCxFK4&FIetzVJKBTU^n?n>cx((|DtarCg|!d}G+aiIuSSiPBZkKn1KngQGS;=) zard*56&hkpBky}-lVxl4K5qqZ3ZA82sF=TJ#8HBX{fkPc>bQ5`uFRjsfAiSOz9%v& zw&I;DkDanJw~PcBR7`PU^Y>lkssB`Vu2!naM@hLUr5%Q9z*ljXl(l*Gkdl>Kt#iNq z&2CzcUSm_-p1*elVEdKgc~}9tIn-B6=?UgTra#7j4Os$igM(Aw$XEQN-^%yiYT+-hG{SlNZH6p}E-k z(YbnMf1bQcj4bQpxA6ytDcgDQSD`cLHjj9|!L4M;$f`%#W>xp~))yxV5R^^%sz+6+ zQNTO>prR{Y^E&aCvrY+M_meQ|~hMUmN-uz0HjNDhQp?^n(y ztSJDCWbEgATX3a*BE{QAxnA8S>uUqfnpntp?ENspgwJ{0dwut&~;5Q zQkGYAm2>MxGF0B*QWoK%|JHH0&R`#>as_ljbm*v@k13@-B$r9AH{)quv+7se@-{)a zG_kjrv*2BAcN!JTa3gS6`b^q4UCca;A1`-pcLC`j8lEi!fn2@t8*43JhY+c%IyHrB z1^9fyt0x@iG51c_kSST0;=X z!oqE0wJo`nC^z~;R5%PFBx1pIJWz7q)>=XFxP08rUQ!NP~Oh) zwr6P%>OaDP?+DtQGNNt8@Lc}X^!^EDc&`kipJVUz6!#f8N8gL(rO)n(9%w1ut0g%`dmG7xtENn#0gee1gAulWfT@YntowrvYI z%2fy1B{LV}m0xWpvt2?y0u5lBu{zDfn5!pi_a{N%uGFYbsYdW|-qn_5CnSgJuC)%f z&GxZl??XDKyoo9|I%-FY#!-sOdB}KtS~Rr3?d|#9j&3yS%nSJ|vpJU2c(DL7;%bj7+O61 z<+A()-txCWIepQz z9vLLesCKt5HkS*^r=5)i2Z}pAd3G&=Ew-tInU`Fz-mo;VdeJ~xcU9mKM|B%Xse4Yc z%y}b)D6D#~aUQ>^mja!np6$}b07Gl`j#fq!{Uf@tto@VK{9pL1u)=>@VfEbxK+0ER{1a`Gdi>Z1wE^jh@glEJm+7k z_f9Ec{R;+kF8SrEYq3Z-`@6n-XmKy`gkE$37~@XVF5Sc)IogzN6RXr-UjIVbpLhAa z$1ZRYCoUIHRymtDvmCO`gF!n36dWa2lnm95QSU#`=5BtTn3@l!tC;8QqpQtG?}e>N zUzOiCf=#tv-APh>qnJWP1|T>}7PWok!^9ewcL7tNtb(b^)j5kD8{t_lm@FDESc(@~ zN=AOIGx{93V2$J`g)T3?&GU87?X&j>0Bc!ZOPlHG2UY==`f?i7NeRd}h&z0D!GZ9W zlpOO-nYF#zUjXSEGv+tR-*Rcfl@O6WZ=J+M7dCOv?a*y$%DU`d(L1P<#Nxs)X@Iy=X^E*vxk*#aK&3zTDPuih7fP zbCrnUW%a6>-8!p!WmMys-PcooTQc*-pijhW>6W7b)q`v8C}=ScNI14_X8YIa4U5th zxBsO@)hQ^WUFG9E*X=WU5$T*n1A4gT|x)n5n(AlKYn92P{(rSO*6TLa?k})CT>AYtibNAUbzWIRh zVmIM3c{Kg+-}WJR85+gO4I-DeJm5|71n=J!5JLEEN+E32ypC2A=m0EV91nPR`s!B< zUN4y{cxmTQkGL>~Z|T^JBzS|6bR^rvp~5~k*Ip~4$4_bX(EX=mrx7Eh$izcv-wvf^Z!{0bni9o zJ{c7xyK5S3>!OaBObl*@1_g6>0^ck3!zkISW>$f28M=21&7$- zSK3*ZFT>U3_i{ul+k}NbT!T;64S!;Ob~-U@SRD_b!qIo*{*^x-E^qaNB45IB%)* ztlckA#$xHK8fo(5v-JV?l7ho2AbJ@gK#aHg7*EzWZ4)8+vtwZXT;*?~c{hc(w+$%K z-{H00(!8pRA_+|N+k~z1vu3AzH`)^iihX^`A45D+Qd9RjHt3T`r7SkKCOn7+(Eca9VhW3tV* z6N-i0Xb^n!@M2c1_(>XmRsQ#5mEQ*&Xhan_W)`_`RwX+p_DHN|#maLB3CmykVh|F~ zi8WT)F66^OhsSS7$;%rcS1$b{<$8L1|3awlZbQItBJ2@2^j{Ka-_8L^IQ(ZX)?$zI z1$b(-+w*nP<)en4q)l)Ypg=jhqu>eD?ZCK7Xew(UU>Xmsj4k&z+^<#1I25cDp4y6* zmXo}9hfF^L0{1Qz`VMf!2iQ@+-90scj=C z+W2v!uGbSizMwRLqmQTpO;P@^&_j4HNW;l{Inr<0IDQw9UdM)CX4&CmiBwyD#UjZ? z%D!PN3vFa$^FVOnZMD@%5IQIIz{+5+Hm4G3QlCM~%t^ZKyq8|imt-tTssCKn{Vn#3 z`FUEqC)QhCCgEJMrnA8w5f&M*Jp)Xv9_Pw=mD86r|3a`XUVmRh?>GOIi3sY2gspO9 zur>DOGh8Pgk$j^LX8FXEFNA2uVGt@K1+U(_tWO}CO#K6Ov0FV*ZgJJxz4cXb;SF-6=@CE*QzR~Hk{_!XS>$D~E zH1?X}HpZ}sb>b`wGbp&X(1GNB^Z79A#a;8ieH?m3oq{jzhaK2;`2(C}2>jpHjHv<3xaaX7@v&HdK1=*2+IL02w!TUGNT>BO zsF0+0KrR~x#3idT92bn0gVwm-Uf{8r!B4Kro}@Bp2rI@;yoNjgL#vp{KI;zo1WxiK zZxc@8r^}|LQe) zbLr8hef+theS}h@N7?|Qug;yfI`=AR%4OpkSXdKVSnGL`a~rbaRY^~IoK2^D>dT^b zY)BgLrdd}?mPXuKoSk#CPSjXMgIX|Qd?TgOu?FFxnka*>qT;UgzZH??+MB-N!+bZm z8m+-p17Xf*{c*SZ`$tWlO&~T!tgasDr(i(=fLB1oBj-xD&`2W^f=E(5OKSw5+%MwA zH_W#djuQ-qBpWK^@KUJ!Bu&R|*9E?bF!yrg{L<{kHOijE)nglcF+jD)F3-NEZ_&wK zI`P`fw{BTT2VvRDUz`4JudFnx|E5fMN23~0mA7HnevUqQ>Caw64WMl^<(BrIzBJvn zGoid-F}KYDKqfV9z%wu5C4D~R9(vnFKj)3_Xvscmgc-Dm$@!l7cibg*Vvo@1Q_&EZ z#VfCZvNq5ZV<8F1usQ4;8E=%J)#`DfMw-XJnkh|2ONrB)o4;#srmSl{#gbwVh-wud zeCiZwG&w^78OK=+|NI_cIW^*R&owqU)OReg9v`pP?hTjVZ`mBU4Rv)$Y%}5_vUJZ; z^D`UQC?(}Q@Xm_KI8R$e;nTF-<9}zW?uzbB?5?@9&|k zk@OT{c-!N{F9#J1G#m6M|2xm z_Kr$z0zk)%)yG-juu~*I?zS_})G1VIaJWJM;c@V(wrR*P*B_3MA++!(89MVFHd5`c zfA%K77vvPs;79@{DZ5e@X5-7!KFNL(y7gS*_45wZM4pH$`-xG0N6EmMrhWky|KmTE zOF#GzOhqU5Pi;J`-(0ZsU`>sQ6%D^t(Ipytj`ODcC{OtrSA(+)-8cfbH~7{VdG0$M zvCIWSS`_fH#Q${%U+d>hVFnTA(4kwcKXz`V`PYe%G$0ocfWM0T>TfR%lfb&#CEW^~ z=~8|ms-M^pa7!17_k{js{GPI}**X^owF!pxXRCVY2EqWEWQ>eE zHd<|wzI$=;KNT+*c_PIbnGA)U4F(Ys)`Fjs2v}Qrbttn{OEA*#;NdPf!;*cXJ<0JR?d0Yi<0=jWzV(mwk=ZtlK;?(xv zCbxr2!zIU?TKvA`fVP$w|5wQ%Bi-@c{rgK|58bGbLvQo0Hd)=%&F+deG)0&%O1w08 z5Mp<|HGz+}bp%}**F>@NLJZ@cZ*2CbwOp<8c^w>+7NnW~1?;xT;lJJ3)sUI2T%aQK z9eo#?v+GdrI)8p_F6bKs)b*1yv6_~R{Je&}!wOpNZKbd6AWe)WhfwYgOg?QMrve{s z@IgYwE&(gQ5w_QI8pGuqTfTQl5Ss+N_|E^iLCSJtVJCNaj`7Gk&R_XU-5U zg>>Fak6ppr(0wi^k4i^KEhsZy z3BWG#v+30b;rSooi%2se^2~g_shkLKOJI0rmwDK|ptrxqQETk+9U+$jt?)%glZ-^BK_*1&~;JuK-F-JcM^k+mNtUl0FiNe;jz)@ z_${BKzqD8}=rb||xog}=_-tBQ$Ixl~+GsM0o`8~{cJ$%R+qTLxE06fvV(Eb)aRCX3-BrymBf8zQUQ(7n*|z!9%_F1;f&*%+?}@ghfL10u zAiU*d(d~6pMde9VfBe30BGw}Fx6VD7Ag27M0&RHQoWAS4t0l`it?8BCE(P6`M{cIr zZLIm|g??NO44nL>Uv`zgr4JkB+fV|o?~y}UP5394;=Ei@$nwyFe^TD0I`YJMdV+R!H_Nu1_w?9A1&8i7TNVT zR`j@i2C7u61YpbyHekNXhits#xJ*1Ma=+3zhb}DAyWR6<1Br^}ay)wCWYLmFptl>t zvZwnpcW~=5?2D7VC(AZA9@0pW;m6Bdj~JF|CA%%JC6d%}0I|bwb1k5)q6w9N01rHHjn4){f?x530AclybbSGH6;%l=%THzAo%QiC)VgOgn7K7#atEt?A&yGmLq zZv;01Ozr`@Y%Q#K?6^a{@XP>Th@(MC4#TFaL?GreUg@VfI+d+1E9vGmHxfVW@o|{T z0fo%a;Pg06dMd)SVdGq}v>)PEQ@n!exs+yXlyU_*mEH+ii_kt=XLgwQpCr%g*5ymFz&rhLPWBsM82_v2qYu2;{# zG0&Cr3S;1}%l4yCH%1L#S(z&*UudBwRqmC+M2cc=S$r|gb9%;5VNSb!s#+`og^_kM zD?xn|QgU5}BzezxEr#%Sia3%H)IVGY&fi?%OQdFfF1V^2ZOUjSzFZqKVr_umTEh#e zoKuYFT*Yw+C}w$tN7v4?DU-TliibX8?=CdETdL|XgvpD(>gQ5_maNiCN zwwM2wLO9~Q_@0*xr-v}~%$hY}e}WLq#}D)iFOz0+7C;W0cr?gG_-=U=j4c^bMB7we zYEg0!L{^z6(X;H6A!`)I0B;Z$E-#T`Gq4tV*-6DWu=qCja56=$tN+iA=Yn(N!~xx< z%D>J`b;I=sd8Se-gyg&1>CzcFq}`u+fv1rjn<)k-Ut>^v`}t;|Tdp0FO=dm4k^AJL z`u>^wCQM|Tfu`?aVCLOjzu>u`g#gR)2}(v$hP zuH*(V*uK(5K^JVM(n$(i3uv$l19M95gP(3Vh;TcoQPjvYQVZcW=Of_@_j*q$rSmaW zvVx$dH+-r{L5Av~>xo^N#Tap3)r-8^;)eK7fmaoj-o9+sVO1;qyctH&{m^0{~~)77MP<$Rq*Hq;2S}- zsQArnt_bL}lU9!Swti^64D?pquQd;EIa}&nI}L1FQI^K>w`{I}W2vqF^1wcR4Lril#xU?m`2M-R}36EapamFQWoiFFu0r00b*&$GXL<|VZD2DhJ=+CuS!v2 z6WT@m#qgf2zif=kjNjWq)U2izx1q+|R;1pV36&&(D+5Wj|O{ZUt?9gADtw#%%9dE6}!p zQbujwivrPvz~gcrgFqa{aM5hGev7qlR&i z+3~$@T&v!pWdVM%GHt_7S0?>2VSKzGm&R0&cydiBI#CA53Ecofhe)hI*^IB2;N&Cy z5U#?!hVjBx>u&yMc<1));)6llItSpLS_`J8b$2&zJ;RUpn=u3w5=7za>>#I4ak}w% zrqvG$iv3mM%RjA27nx{AfylY?SJ-L1+wiBBh&wURGz`=p{NxON)LTF?D zluH_3$El+SMdvBC#n4|f`I^2;$%^ZsxF=oGTP$S;bxr=1?_;<;N~bP+lc>s7UVSE> z__g0hX2;m2b$;tSL9e=yTSox~^BoabzclCM$c1wR%$VlJr!7diljC^xHUVElnWAK3 z6WlVNkM41CJ!70*!&v+ZtW9kAHi2riTD6fY^Y+D!V$=TS0x+8Ia(CXF7%x~B_g3lx zy?{OU%gy9{f4So}PJ>_WD|9X?qh)A#^6Dc8@MWU*ozBd=)*N3aY!hDnx_Pm8PgeGV9VcAb^7|BN)qPx>;% zXfWdVKcD6Oel1C#;kW+X{w44gF8z;LX#JEHEyz|>BlqqM+&v=2u*eP`hc0+zF=sDn zzGm+0rEw;V{MsGZH490sYO@75v-3Cgf?`1IXF0FBa1efMci6-vMx^`|Y7`!6+r7Ri zWZd^a6Ja5G$84RyYecP8JBvpGAv46ld~Tt6+5y)p#&7R{A0-Pn0k_k4=w~)A>u${3Y8EIa zkcf!$Z>d`jM}zq(VCk)A4t-p zgOiCzcDRYr__Vfx<)VKs)L^ExZPNWU&^*lQO@#cp(LBj%t-jiGsT3wgh|UG5`TEu^ zEpGozbSQo6n1e@z`Rflo0H7s2xR>gEar!lJwUP092X)Y)9Z3QbY-dSAodtdUeB*L2 z|DY^c!qQnqK z0W!e<7~=U5X=}b8{RT{+l~MH@MM4{w7etr{;!0B+8{BAOL)bTsxA=eTr_m~5>?f^q zWY;*$uoCZ|f{M0O9P^1BDB+|YeBp)$Nd(CM`40#oN# zg;YM0Td^`=suZHOdp7w~+t-x{HKOTJ(_=4C+gLaD2hfJ|vDyiQne~W%WrzD}BA_$D z#IfA-6Y{w2xbGuK71s+;p}Qyt{SP8RRYhqTwF2j_?@Q%Tcw)`rGW_w^N&!i^da}0VZ)5Y$O1~k@@tvm+$TC z>p!fqt#4=PB3-m9$8Y@Eb0Fdt7J`Olw@-$xRIe2s$aM4J979m;RnFEDs|`w6;+a~_ z!UltVe3}Z5&U?PzHG&egE!umYEjoWxPB9a608b?=IwNeQJ|*4Zu!lwQF}14>u{&19 zp8n#TyW21N)c;s7;>Yt!(}UcbTpJi^-;DjfP%#0&Ll?ZYIa{q<4(8%p8K*QXY1)NP ziQil5HQuc}+ucY&EQ|9i-%xrLv1`_4;gv=?Ak{+)ENs1L`SL)>c6|`p418M zTshNp@nmUR$HX=ML1bV50?e?=8BdH$*~;A~KLBw+7r^9ya_V1KU2@*TBJ^jRT0#=} z6Ms<1T8Q7qYx_gH3gf&ViweHw{n$xoT4Y0kF};-5f%us61!uT5&@;R5kPCCtDtN>h*y93I@=c zDoaR|1~);;HK4iM%#LL^Yus}MSvpUj_=Bjl+uPIwatjRieLElG`z4(T_-V(5cqz0| zEr=j}7IdCSk7m`^v|8<}j9y)*?&uvHU_6ci+yp7{l)xh0)I0m+qVsw;tA2r_WUeaS zM(caaiyO_3!AMT~5G^>NI_Hzz*jPIiwHv}7J~s!5)zIqmtlzG*|7EGsQy_@yza9s~ zt?hV=acLJ1GPS5NG7oUcVqOs3Z?WDE#GCFs=#QyFq%rVsl7*;*o{~w$yix_B)ozFI2JN_vX#*>(eN*WX=IO%f6;-i>ua}!2ux2K8A*sP1Ih*8U7|Pwc zW;5>Ge=2wCm_mJOJhP~ALd3TQD-}qI<^Gx`zwOCzw(_ulQy z<$Oy}D|&m;ieYGE?GHeX1q2c3K-MpQLs&LZm7(?HMcLexBcUujFmiwZU#0dMcR)t@`= zw+z;LuEOGWBpI<=^G8NeY0|^fU(Qy~`z1>UbMpo0d;o)jOI*^UKwKbDRG?ZrTw~TF635KdcVR@ElOTTmwPzGhvfS1Muah*L) z_dFBtWo4Z=O4lEl0mq6J0H&M&M!DwMf^YNIZyKqH2l8N7hQbd95@Dw8Te>R!#__>$ zJ9NxzaqP1It}{3$^R4=60DlpolQinSw0}xy{YH7{c5jh#pxB7cWrG4yekVBBEmjv- zI>zoa!_Au+8sgW%72+JbrXQjg2@-_5i*a4`XIO~5zaCT%7$*Y!FF#{*oa3aHvZmr< znmp|w`~bPozv^ohk^Xxt^L~re`{*sfv0N#DdwBmOXjz}8 z-;J~A_VPf|uq_SS0JMJWi2}ORsgd4LPHV~v@Mwb+Fl~ZUa~p|xz7bOZ?|NwR>&_{s zv#A~s*pe@3tiJHVk|OL<*9a(=B(K_f_cF?f;z@ z3Jv-8Cj;<-v`x73ldJ^SA-0^o)&DSY04Q0eZI=ZH)h{iy{yWoz{DR?9AV`If=ON$zRJ)4~5EnEk*v|bY=68o8^8Poy^& zV5-^8%P)*u%~Jl?E0l7?o{wG9jvqzs=I*qs9YJyFb4)Nml0O9=9`|ZNU-#hFQbN^bsArS!wyTkD3` zK`a%+-N{hUi9~^vZ0<|>Y*a;7ST|B4dIS5m@YMM?_`f$^qGm^wxo4p~0SiJ_)#m9` zxcvFP)ni7pZ$A15le>Ffto8DL1g09K1W*f}s9PA8`&`;!v>pNk>^ASc{j`6N7gZ2o zz)>I2nsL%|%4djW9vlpohZsDirPAl^PS(XTu`w3UH(%T4%$lEW^?rz+;Dgp=yUNpA zcN)cc&K|kBf1-QJot=`;4?zYE62c=ZjQvg0B9TdxISAYC+<*n?_ zGV@O{aGrMkd7yhZqNjkPky$xB12S$q{Gvctz~V8>H}}6c;QB@{zD%^Rg zY@2|e)q7kAI!m|`@VF(7_uFO*XOL&WRJZJ+qoBiNll(j<%s`(5Nh)|qv*8ybmf2+^ zn(?pguHk9>d7ZF(LTr|v$2|}@@EH?Zgf*s}_z<71mgs;F)+D4X-V34b zzUVg7OOk>GRLzUv+8PdbT6fKaMOJUkcKIw>tiLA9)xav&SNZkmu6=Oy{h|zuD&2iq zdLcpXDBsm9*Nj$Fk^PSQ7iYuQO+EW7m?O0jT3s9orPhWAxfMqd4X8ZjFUv7786aRy zjhtqQV8o92aPOb22#uSR`(*O%UIGRgFh$lfb$;ed9o+V^T+t8$McjT@cuh5VEY(&# z67jN2LSzbU9J0qnC_PgILz)k+=rZhAZ{2@#V;vgrE{>wYJz&vYv?vi#BVDV?__5Jk zAK#z3`*mfkfy;^@zBIS6uB^~mYa|h^ja?$f|8;QDYA#3~lRDE)tN{HHy$yK@@6=!6 z^iKfPffdiFmpNF~5A^hX$zmnL-MqVEz($TE+23z2kFDHc>7-i!vQE+Oo7M1u=*;e< z-&?8(Utj&!3QzNJs(xLa915Lim^zy}(-OZ=W)qI}Qgr#H>;ToMh$^#x2JL8arlAuK z#8r@^(SIF8IP8u}RiX)?$31f9$X3i30oU35SyU~b2CC2?LE(B|u@t)lxNM!g0ia~) z5k7yH!jKN+nf>#IUU~t>wm^OJv|eA2f_BY&sh!uq$MbK+*Pp+4xW5|=JBPa`<`u4| zlsyJLwA<9;T&(xS%I^}g{XT4@Wc1wdkw8%ea#VH7l=MGX5pbJAL{EgMWQ4l?lj=pK zDflq7+r?AgPWkA02x<(0lOf?r<0MtPwa3dmO=nIQ#hXlXIL?r^M78ktS?bZY1a|*$AM=mhpqCKx zkZ8L6>(u6P;zfs^g;$1NC|!xbdwcjSZY~gkl8?&2_6|zx8aCURC!ZsIQLggr*xP%< zlDvU#Xrr-Q#N3`8k9w|PD5Y@Kqu+g3Iq~;^jpYp4B5)DoHua}Iabt)tDKy@dA;nr; z42i`X+XO?D1`9#Hf8{NxUsjz{N=6zB%Di(7NYZ@KD9JppmeKpl_Q$B|;m|KLNVz^%IV&*zWIz)gyTs`Z7_jx!3vg&7$Y!tn{BI8|?x(s`gG zp`z!1txXew<5V%80ym7oWggf}qu-M^*t~m}JvDJr?U7a;xJ!M4UAAox5`$ZM<0*0@ zpJ*!gcBnh=!DQLnD|hzVtCvB-7F8gAOC*D7n{#`w1Go*FtZf#q?|PrZ5y%Q_L+-jY z)M;lu1{F$?t1eiK%bkpbc)w$C*?msJ{=fT@ZXInf8*c$ER5eUaUE1UX@Q8>>9I z%s##MKb8GYC0i(sLU@q1-h}_S8rBP)k9~aG*1~>MKU(m9M{+Q_@RsUkPD6g=aoju# z>`aAWJ^Krq>1iSois&ln*!>OzCb4JAM9wus8`*Q#`_KWkExxXhx!4aGP? zq%>(((uaNhPz0=f2Qp@DO$2vgDDfnMv@`X@l1=a*2u07U_-+5NnX3=qp9+`IG6b9p zMyu=VF-2Q?Ama*)D`l~FeO|*r(A)Nj+CR&z^;P|lkXbQZfET-eR1JMHR8Iwg)DMWh zsQ+>Lut;FeVv~2u@}jaapi^q8QXOqF#`p+|-CHVDH*h?Pfheq?Tlmy^e7?@8#CdAliw#wO?jpgM%wS{?%QVL_SPIiQC|Z`#0pA zI|M_|AHk8mPfV4nDjL4}N&6hRh6~>6Hr(O}w6+9tivtrw zg5O!CY4pndlZ7kxj`?JKgV`E13MmMeo7BGl;b{`);?NY+nCFdgzA7td!;e>u=f#Z# zDw?zny&k??llr9R8fR0VZx~BA`=84=ksEE9{eW8nbtUZGO+xnp`6ww|FsI=TdStFktiZhID@4yK ztnrI+_McNs1nEOkMJ65mvh9dpzossR51o}5)zE_ICS1^EzG-tr{>BpU7(Ic%nx_r} zl^W>92yI8EKC|5Yulz_Uzyj1zzyxd{%{6<$v(Be(nOwP|O6@1bo>yjpLE+H<2 zPp7YW7s#+RYrsdn410IK$r$V#-n&j$Oj6>~L|k(+g#eZ|Ok=};Dw`ekFoJ2rHZ>_y zxw8VN*Ubt0oUu=U1=SC=p}ds$0`8f5XNqJ;z@LYXU#!GSTPWf}b*xG5V>#Kv7Kn_n zM7rPJlJD7OU;J4z5@EIsfaAZgg?Ei7^Kj_#Z8*9ZM(~|bYr8+UU{!Ajnl>M3TeY|x zaoc&+G5ES1%+_)drRGtU5~(n4DFT7kLDs!nNvdW+(T^!-YSZrH6RfT@D#(6OPu?-I znWi*Si6LcdiFoG`18w;B@8$0b+fH~s+@JfK}^f(5|AquLp4G+U60A$7`K16wCKwN+k!$b15^P^~Q>wq)fZEDjU|F>tc znbGG!4C#EtHm=n!68qLI7LqF8?Un_2`oo3W zkq$h^y;@$Np2ZLUptgq0K^GQV{-=`9Pzu#&0}teHJyAh71Lv*cIp(8SQYmLv-SoJ~ zH~DurrFS+jgeSZ)(Vb3>8goHcoUnZ6eT@txX)cf&bcfG==q$)8@G=&k+EvPIzOt~~ zC8t}>L#rOL8eO#uXaau*99ww&;u)R~`zuWf^*fv$lqTTKJ!EFpR)*?0uHW>lwuF8n z0IODOj%R!6w&dj<0CmkZfSMVRH`>au{#vxk+{*-Hr(<@y4rLFsLRcO~&jJU#kS~ z$oC03o*!1_g>oMnTlX3Es5(0f6i@n9tb`ZHLl_asu#HyDCT-Y{9l$~gRiIg8FW>;W zeYVGTNoeuPLEaH-eSb^^{|2FwA2pJ%cDmfwLN#9BXQ#`9gx4HjQsn-GBGj$X6-n@% z2PM>Jx1LgOAMM=r94_eu+qs;IvgH>i!<7jMqbg~r?SU3L74T5D7c+eJ-xjS=73A*6 z+yU}PEGQMz3CY>fxxZk4WMlcIhK3b?J;67h>7M)ert&N2*YmaUDX=UL=NMh(T9T%{ zqoBN01xoOA8qxQsbIUv8w|DFSczQB$kI5Tkm7DTxnsHef#C#JzNh$#M5v9Aj>weD!4 z3>(N+8g~n8=`G1{0jHzf_0~6G&2E-4Ar~X|fZOP_+;Yyj@E|Flo&+I?$bohwN5sg# z(aC*0L}%M#O&`FW^2mXk55!@@8e}FVqZWy2?w>dR9T`++(oVVU#PMnrmk_sJl=m+hn-h$5|uEZBkF?h6W_Og)E%7WZ+ahWI_) zqT;s^n=XDppD2r~F&#n8*h2$ylxrHBRMQhLQfN1viG7*-K10JA%jNtZ20Hgoq9X1a zA@lyX(yeU0G5T`DnoM9nJ6B1%5*7Z@JIB7E$c#z?<4gg9XN*m$ov=rcik_m$umt12tnPyDt`X-5xMxh#66JI0EO-*$Q+}m&bFj*KSOUT6AY7pMwwkZ z9P5_)s1sYU>dIx!16d?P7bU*UA6b0o^2ntFcc5SaRH|`Dl&cipD?(4tpSk3^-QD+m z7OtF%n#;UCbb&iIAY+~Ob4to&(agR_E@=F6SJOC_%EILiuAI&rSQC&VIH1UWgF+w;P za%ue>Xh&;q|Ftu>m70D6Qz&>=gf?L%62joV0tk3XLL56;8Q`;I`F8e~De4!k?%j+gjMuOY{Vd^3!9nfzogr8 zGOYJ^QU6SZ&c}9d?0N!z+#kr0%Gt3J+^HrOE_TE3iAAY8-2buhHkX6rND4hg13l0$ z8QWGiTR6y$;o6?f*xz)PJ9G8{ht5YU4ahfNz3i#vjQ5_fDD`_oYc%okxT=|CCU%*wo560%j)F7kA&v zl*a+Y>x-H93*9y!pT)M6FXndC_0Cg!IT}k4gU3#f(`)`#II%)<{Mt6_j`ITI8QZHE z)a7*2f)#@*MwaAs?mozRF}8=+_JDU17UYK!I_1JpolqGS36WC@CYyDr^-l-2-bDsj zTN|1%!A7ImHQKYGcK+P^h2+U#?uLi*2d?Ag)Gh zq`9eZ!;AmEmTf)$laVIH#75+CYm+5J>W{H46>)`wKCOwmag}R3xx3u!#35+#^taJr z>d2!hjqm;Yo<$tNas0%dIfjpa*DEz8 z$@h-mf;(%jv0X|c0*sTV43qc@OsmGFc?({pZLyJDaM&mSi{@7Cs4lt{v@9r@QFfEJ z)z0sKSUPIqClkJBHbbCXgWN5Qt_pnjl5s7vI zob1zK)ZKlf9>s3|b@ikLTkUVnkQrBIggyBGC}QUIl-&RlZYu_plgkltmspz`^|JT+ zKNye~!9+D6U%@*Qt9#I?QO}i{VERXGMr82hXtwS%e*Z#I;}Pv<7)z3<8Llh)^k6bM zj;Vxkd^P?laE;d^1g2s0{+KZ5zzS78{;j@hXe)$m4A|6SD4d-~xV(XGZTf`S98$+g zd1N`0_8Izom8UP-Vs*y#2ZNN{Kp7x$bqC2-7qH>%GW>+>Z6yScX<1gTO}J*%e<~V3SZALhT5@A^Gk^T{{xIRV z`|Cn8rg5;as!Mgk%;|nbMzLh5QB*drZu0dyr|Yl$iZ`A~GEHf+e+Ro}=jz^B-tX&34N zPb1UP_Sbg+nygd|9=X0ZKA?aALPXyH`2f@#<64{Q-+JG34~Dpvat z4imNa65LZ}f@A~3w07uA&11#@`@9Xq1UuxE)e8G~6Pph_Z@;|NNMN&)A$($;k=QO3 zZ|=elNOA~x6nku>^<00`T~S7MD6@7mda?*o&IY)y<(cQWS9|XXw@?eMF7Pd9WW zpt~npuKCkVW{Jbc^AAh|k{eUc*yKfMR&ygbtN(nylKaqTNI^^ofRBVSYE#D94uBB# zQ?7C6`7%P|Zk?g6Cm90K%t2iLO7%{Fl}PlbpnLVgR!)}{ySUdO*qDX@;!wa{%_iag zhmSaa;4p7rAni^cWP69q&GB3;KuJHnR7QT|$y?Bx>fqqCrmNSe*@zRTw6 z#RY9D;sc*rGvj-C_|CsD{sah~4VKb%CRqVd3Ie2YSYY^Ms5RR#4(h(+Bgvp~wj51z zMn_d^1I(>2$Zi&Xo5|1{_)4X0D7~7i^6_mzYnRw~R|%hIneT1oqQTZe;vkWOlDErf`WZ77it<{XIp|n7g1Va*t4D{V$c~v*-xSwxLj{e1w z07s=1ac?lfGJaYBcW5y?SNy}2=9+c;I7&tkd-R>&6^#n%kyXNv?CqA}Q^P~Xsc~A# z(thWr#!u-=rr~3YkobcC$I-bsGX4F3T=$D~A%vt{y115WrRe6C69T!9XVdc-)@fYZojPZt+AafH)&9`dft~oJs(0jZrde= zZ0JzF@l+Ydt}JOX1h9PCWThJ1UZcQPMo6(YFkN2a6P7Mr%Uma=5-_W?6+frp?|e%P zrCOr=(ulPKbtTJ|?XE^t**bSe?w$Y1Z8#fbS#+YFB>_FISUk{0MIXyk)+owF@yFP7 z-6K-{cy!xYxse#;>VjHAf0Nj^9iD*_BqyZ9~PeR(junMS>QqvO^S ztA1+ZsO96Zs|C5X95@cIHh*X?Xi3_z(^6UCl!sOh76r$Lia);+$Me0iZ7wEYz(mVf zm>DC+j6D4WtC_#b)gO-i`1Zgdp~Y5KdnEXt<-pS1L5(&|Tt3y-3p$E|F*Aeu16ud6 zY;X-pgZ!hgJQis=w&&vJ6W?;fHI9L)A^^a`mu!ZceG3q#H487p2YVBb)~+rv>L(Eu zl-|Lbc+mP1)E*naAMDorbuX~r_5%xhcTCCb!-88*zm##$4LN$4(;gZr1E>VCrsxr%j9vl?VG>?0mL#~h3;dZA2r)=<-Y zqXzW2W2q7<=CDnOIO0YyYg_$sTXy*_#hK|@yNo+f+k4UB5uzz&q?3=L^<&b z48hlr(|MH#Ig77}d(k}m z8DI-N#jKAuNSL^|wh_z?--g|i@NTb*tX+f{RQHh1JckS|8bv6k71*+qo)l8O1$?4P zy>7Ny4(EL%pYXODa}ne(uJ9@%>eMK~4?~d+|HQQ>`j$*e$P$KP2aj_#mI#mm`?@h2 zD||K;=}!)Col7`VU2oip7T}^Qn|4pWbSgTm27%%^E)y?d0-!$!_%MMop9i>1%G!NA z{yKyi5a-=P`lzeI{Irhp!`Mp{(xJRB?+-1aWct;EnXETwn`wy=Pw8{#-Y<)=NZD_> z0LZqcbjv9Wfl-!zx*fU>=uK7#WrgpOb{tjVFpS#Xhf{u5gJ0N(?%+)RxN1DZD}cB( zO5SF6ai_xj_65d3qEihHO9dqS^o2n~`oR@3BZqk9`Zixf>HN8eW|j=U{PC`uB#g?E z2=aUx9km-x1->Z@zr-u2U&&kY8L?e?Mtk8|C7pofyEH}_gt9ZwgE)DpifZ~|GWw}k zrr6ZQ&{F_jznO*iQMIGu#;=`H!gufS>!04({#1Xtz&>b~W=kc9*N=8<4O+tl1cIPy zZcV7?E%44+Nf4H7NJM}^wT{S?mdF}G2vs01jY}#-Yvr}Z6lAaBSsuBq5i1v?V0|dd<4pdtF*D^v(Z`$4NG}#Z zMdXtlj^?`>*`VSB^GSjF77ber7eAHeN$X=y?Z zB+%}bNzW=ZGb~8fAk@0GBEeTfNa48VqUrwsaV$vRbxvH+aOcU4Xk8HI>|mqAQ8XkF z@51td28?C!%(6aG!EC|rAmro9w5P);=T7=>;~`bL)Rsda)}Cw`*uM;gP63FH50MZ+ zd1UhuIqs7hn4((Jv ztaK3-IGz0`(S58z{6iS9CX}^0&ho0!X-ePxq)+lFuIeD0)KWCLt}IEhaqz#m_deyR zH$I^xj4M4|s(2%1YM*Im202Iq;5VW5I~a<2M{=%HX@S_suNFfB&m!Z6%w^cUF)h$|rh{Iesz#-qY&I(wE%3ihiFLS zYN{#<&+SPYdNfWHguHn z70=UT6N(V`1iO8lC&)B-k3j5?z>Z=0)9y_pT0B!xlW2x_($ z+??|n_t6a?@h|Sb%62%E-=D{%_ejR(p1KUI@|%DPrP|-GeY}~RJw(|A4xrsQA>{Dq zx3}IF#51NE-sOv*98v1gG1fqhSNcB0XYAKcFR~ezoy1$X)b(VsXcs>=J^zsYVBU=t zzRu(00?aq+aImi`kIk$l{lezr#n#G22!1uv$|JKR#esDa#q86G9h(c7AQ_$=H)7>L zz>wKuL*b2+5Ai3nH)UQ~I|vF>6GM-g|2`c4$*0Ei06XqIrB&W|Z@qRqKxvbjexEOY zUOOFx~(OFifDExrj4_?_dpWUx@2|8Jsk8f_?oQNa9%qks0;qTNUR+ znU9JjtcUEawf!RknF{zx)s1uRRiPdf4%>+!_{TpSJYHb!ox^wH3*8HDq>1o#txh+C zVq&0xxN-$>dF}=1u9gL-;Ph<^Kp_}S)PQ-2?W3Apax9HUxsgVw5($X@$5x94`$oRXHlh1z}rCd2I3l;md^{hnw z`O&_Kp*L(Hd4$vs%+bpbfFUz0&s&IMLsSQ}bu*d{293oIxW)8LAj2YBI@QY_dRt#HxlA=gB{#L{J}+ZMb5OOC?;>?AI^g6xuh ziYpMHslH9mFh4lIxMtCj(02WoCp3oS^{qtlP~}gPT)P;RKV0xN^$XTSJRi*_Ul=4w z0rTUkbrFDtq&>eoOeLRDBzlo|j1-;O?uWe#ANjQI8%{k`SmpqXH!4;;gdXCAS0xyx z+*>>QI!}??IvL+O+N@1sytwWnq*4?Y!2+NW_m^YOsFiC#de{7~3WHnr(=GofN78$% zR1I9%=X&Gx&)|-K9TOIz*XBlpn7dtgd)dOMv~ZvgaONFJE&uEaV(tzeF@JFPA1e<& zn?bM(XpkcwWo1x33^vO2(_Sew%w+d5r`*<$@fjPxsW$Q|P?;?Uxxje!;Y|g2tdL+- znfEFahhMm3Yb57W!9dm_7xW=Rl7Tbp?A3{U>;G1nZ|F;-R=9VSYmPi)rQYBAB_sFS z<(Ug#$JXfHupT44r;f?1-;EvnpWI=$^+i8*oZQ7YE5AU)Uov$$EZa{f8!a~)i)W7~ zJ*+if6KehFii8j@+;q<1bTG3uKVMm)&wS16dY#)A2Nz0s($?69-~FF9(7AqAaquGc zm53*0EgLJ>t|~hP8Bn(Y<=d_*_dfO+#bFl!Tr6Eq5)jYqs4UGCRh|W_Udc26V)Apc zoK?7Y5Izh&1Go9@#vlieLU!7RHRbYB^k%VA`9E+5)k&`vz27d9W?F*sdviSSG1PVv zYy0zQ>En^^)a`xVk)SDy5l+{dA|sh>&fNUvmtOW$LrBXXRv_iH_7&jR+-A?ja-P0xmoSbX1({uJ)LKZN4m6C~SiW^`eKUByB!hRVY9T|;ND zj?45X>KDtH9Z{O?73G|>qU$(|ziq)77y?xd_ODp2Ma^nAhZ1(7oer?!!QN`f#FeKs ze%5wn1x%G!m_{@rm+DQ4^|gzCNva}7z|6*}c>P6%5yO=cu(o(}#w)1b_wSC9daLwE|Gb8wYU6NTJ19*CCCqeSSjoYj^8|4&^ zZo&Z()PmX2{Cbm4*iV`Rr9NjLdtZ$ATxeh}Rzkx@duC5xE-YjA-zEl2Vh0H$Q}woZ zYI`W;FCCW*>Wa)5+~HM5gNXr-OvZXAeYM?bLAPPsjFvBGgapVC^`;=sS`_d1ym`&2 z^xQ~vn(c)*qYXMno%Lu0wMt`-wN%4hi5JPNuNci3sdn3F)ZgojX*7$a@2>ul^CN#p zh7Ci<{64#Vr3(`pC~EiPwEnqY?!$`7J**6Al-3br8F!0q;AqV|wO2-I^=g8eUCO?# z4Hz`A*bn*p!?DcyTs2S?1XS11+i1dCY9N&PC(k4c+fXMt-BHn}n?l_ragjp$Op<;f zjb$)aDwX8v)f5sF#;KyBCA4US&x2F0ot!P>x8wBJKHyWb`qRt|%y93pKqbo|Wo-G@ z(rL2WO>Eh63vE%>JjGJOrD6v}h)))2p7u?3Et1_4x9$%1FQTy*&?4Fjd^*;S0PE1G zU@~fU#fL28Zu`2&+X1#Dfv3x9&B7$21z~aSDv-p|6wSxB%mD5^kohnG$SL)U(Oo%Z zT&6jX(&U6X)fk4zk!}9VWs|!2&=;>6(pxF`?JJGFBLj+4`siFVo4v{fAuNv;&1OyS zWHI*FKl^4`=O_D?iM3n-NtFO1K@PY3IMIE@azx{N{<{b+Ygk{3XTh#Thp?K7y($v- zaN}ZiiGomrpO@(q5C$k)M zg~9zLP>-Q!(K2w=uQM@jF9I3JS`3hS-Sk!sMTO!Hxu^EM~uMfK3 zWc}QddE3x;4{mc6a#sH4OL%NSJbH!Dwe+s``L1CM`01b7bzZ%fzU~+VJaCXG&e=&? zKO4`dH&>FATwl5s>Bo|!ws*@TG&8SX2sCo-2TsJwb=Q0B?xm`QV3%?rG)|~YeeBVP zx$ynk=W4z;0}0lVQasyBch$yk_|cWNM57h|*soOEwvxK5=mj&bb8<)k?3Q5Q*L zhD4av{$T%<1vMQX%Mv781XsSwL4d?v(=obs%nhd;iZPF{i*4Z8wZuWhasA##sb?L| z=+E2|-e~*<9x@(e|3V-JVn*WLfJ@#4MMy&hbOJ8O`y`{{5 zke_FT+b(RwSO3mBF4R6(^j_pG7#)u|(0p}!*8+`QtPOVvGSEE>Bv7rr1o^iuYxp9@7 zUoq-C+t7BwT0=qv@p~`pV{#1+bQm+UoSsCS%DmqoB>+f>S*BssmRC-?xIEiL0<=kT z0e*`9`Tyaf4#y&%&B9}8cS-gGdYxyxg+O^OVn<8J9uZIQXsNN~r;V+c>xdPx>>Oc02Y0u4ti%qRAuuyD>2rs1HuF_3{Srg` zUQB%WdhCb@h8{RGW7*A~dvMC2#2^;<>-_>lVv2Knqo*Y8fvt4NkFlE3J>spg{oK2? zu->4Yf2@7IF??>{a@zd~;!*WpQBSa0mngk}WwcFeC7f}0`a$ph`f#2SI`bAb> z8>2`dAc*pRQPf>0c@kEx&}5Jmv7BfKypW^Xdi=0lC7^ebAv*{OfdN-`l${ zZ8_!D*BY~z>L@?SI_Rn9zeaRrIhz@?Uc0jQSiIm>SSCrU7SofB2LFfHXwyMf6U=srErro`%)b z{FfuK1lvjWne|1cL6U(>&~5z>{zkURrXUyym)QSCJZr&`@ucyY&m8F}yxuWxVApL-~Us=LD#!5|XTh zO7Zc5)Rx5SZ)OFA(bl(ZH(}8hr9f zaH-C6n0(J;PQOE%sUuVi#3$Fc1e*MzEiNRM+c@upMcY^!b=%L$ejnBEIXK=|QT=Gp z!)9j8WizZ0;Jk5(1V~_uLq8Q8J0|a*(p7%jwM|5^aOF`|mNn3#syCI(OndR029!;d z0?4}+g{vu@`^k?L1hB&M&yfcbrGX$%1@X<$fAD@`;VO$$X z>_a!OK9%^>BD*^mrZ!HTW2(u`YVl{W3z04@uODzcGnp~CB9a13q@`Z zCtD7z$^aJNnZIG`S{ti!K55xqbx`qyWayW7&KAR0w4|DdA8FgWB~%JT^SsEc=@16@ zKte{ic&hI>dP9ueI#GO~?bactj%3;=jy<+|)~?mEmWD8u(ia#T+CF(t>gX8Y>OJ5J zEv$7wi;O}sHYj_G3ci@uo3NRn*!Aga9%~QC76<~VzGkrGgJ%M<66;2WBt|c>{r2X9 z_!a(`W7e-MH6xH`VF{#H_0J7`w0^32&$+w%5FGdZYiWbdPwbgo+{YeTHYJ68BJN-q zZ~Rlo`v^eWc7#ir9jHt9D2M)QsU=*}Y5b?jI;VYwTOiv2T2{+Ol%l*GT$}fXVxJ<{ z$$j%r`7%8wIEdk6SogO1Y3IR> zkR#R+eNS|dOprEn;CvVlNz)&D^P>gxU_g>AqM%4}3FB5-ds{3&0g1-T|CSD;Jk0Iv zAb|xEx|@k0XtMALkPG|P?2E|x5*;nSRKr}OW^PA8)jkR>o{`FLBfVdKpjRJK!-`b@B#s6Xq7=E>L*8WFqEy0GjH2URQ zh3rTB++X;H_ZjmB@oUKEvuu-ovNkJOY3OO=FA2F2t@|?4DUoDy+)$$HmKTUGnOPA}2A2aL-A#9`>6{KD}vo7*9U z1Y)!Gi+6mGQu7Pqj)l*NMaQghla;5kb<=cu`w1*>9@|m=Xva!b9WTd{&u$@}&(phU zjUzW!cXvUa+Kh+#RScS4%!_1EAP-&cK_vPyS(Q&MuuKXtYfKjRyKH@)^&W@^h^H7Ui?0W`%%X3BBOu*dNE8f!}k|?cDvD z3PTvPSw!0gf9HL{_jm`^wvg=PPh}n%u!Kp-7o8u>y)ls*Es>qWqQ6X@LP=n#g-;1% znLW2Ge;a-T&C`6s>UQ2|Dh~V;F2mvnNC?P$gZ|sM!x|D0zwEXF_N30NM`RVtIOmiw z)octQdbsARJW(HjozSIzTT)>!jlW$xWwztl{9k15%W(&26kek}lr8eBG!AaR^N9}t zKQ+u5$G|zU$b^1odxRzH=yoavDQV~;+mWBy(oHx4;%1&cHlEZ!=u22>bJgRt)i? zT9!H5BnWMf6HM4PRXbBKJxE5$w%$)~j)zF7_+-_{w)XKnr|eoupb@$wS?lURakUD# z(Bj|KjH9XfpGTpWsIQpsZ6NTx-EQN?g_$K=mIN%Sgq%Ac%jJj>HTm?=(TV}0r7#EN z-i!|Bn)MvyvM+#KgtOV&zp(qFEBEu=s1bFJ>U)2PX-siMI@is$l5Qop`Y!u2+Zw3+;r7`$9(+2Ol0YB7lhn-?A&}9BT1M2Z zG+3AgMmzE${2RqRz}zvbbcYo9wK#x_dLzZUNGEj8UOX8OpHaK`L^`l+!Y0Pwu2;F; z|3(6Op?ycLh%8!o)_n(D^>@_!>y2%#{s`DtRwDS}UyG(OjiMbPhsBLx)Qrz1oK>jJ zFOV@*2Z#Apzg;}!`MZLX)xr#k%`g-beAcmpA9H6m*XTG}++Na4%qh-MZlp+Fu-&WR6Y(g3TEf2J{VD*UOx|GVJ(6RUUQz7ldLqvc_zSFjuJSOLLOLie47nR$QDDu4N@uIu4Sw;9~byc_GC8 zjHWa2Q`Qq`_7sJXx&~wcR3DxgaONQiJ zY;p1zTwbQlB1`Ig;mp9uY~t%X9mcn5o0t;T53d39VBup)mGTr=$;101m&* zygNLP_Df&xrDb~9)kg?$$03XvoMau2YB8ZUBa~dc@`VwbB5Q=X=`SN< zIhFC>!kmg(?-j~OUDJx>`i3iEKVMr(EE*eUtPAaqVp@m?$Jzcyts^X!Ka$f+Up})s zvAVEe9(UH*!pQQ1aew0vS}PLdVH2Lp^DPCOkb7|-A4Hur0rT*7L{^@MMn%TJ5!8`3*z0%j0_-JOxEa^K9W1JU(WJo0SG)Czm@r5@$OZYyesX~9K0dd@`0#v+ zLx^=Q%F63xVtP>{?D_m16otQJ2^`d`3nn_tWXDG35L{vIFrlV;1jey5>PMyi!PNT6 z+b~!2rPub6{|z^fLCxg4jnJZb1U_2lj|MQ(0Vi{9KxpkyMv_dw=~FDM)Sm@c{A@6F zAy<)DN9g=WrQqrtX=m^=Co%&x0|KxHCTxR%-8}lM2mYlmLz%IWR&+Oms4ho(!!bHs zJMd`jT}n`;Gh8x@QSj}5-^e4_T?61UO+8w&o_Cn zy2ej{hm5^l@oAk6{{%FbS7o(T4mHe4W4YL5;QvwJJVTiuf@629>>Z_ecr3cDllBL6 zryO2$`Q9)u@y0Oq+vVcTtL=Q(9sMT-m47PY4zET3*;%Dp;YVr)Z^5~Fyj0#ti}T8N z_fL4OAuc7!qfO+tfqOEsRU^tv{W_6uHMp%U{EhlBd!x{G*}w=kI#(r~A&#f6c{OK3 zGI^fLsaHSOLpnDa`+11{`W<5Rm5$JXRl@e&${}C3xcqBPCB>1gaIspw4)Yp_9+fVsJ)j^-b0LySSAH zHB+nH6*x_*(;gMZ-%gUzBVb>Do>zRejmx)?^9TqxAN~?Wxq|X)7-xTC?RaXUgajTfcfl`**IE;M2PN89jjnuq6JV0nQXj z<3qi&)YSSNf6(~GOgzIAJEUW2o0Phyfx5?SQ0L0VIl|9|d-3N13!Jzg^~~&+JBsBZ zxezCx#ua+-~g5nv~OZ3-ph z%SEaVe@~mqFpWEAa=Q`vhEUho6*zzFK>t8BRM`#} zxlUCk7K)TG_$gQ8tEx}=0 zxjuh*WyYWNa+C`p6gvZbK6<6GZo=;0LYTv%MfDq4_`r&};6SdI#a>4+P6P}Gk z5)Tb@IVwOZs-u;=%h2$G(oF3DD#dYuTogU4pw3=5L}1zhArpjkMhTveUdef~vees~ zMKtM?#lsgBF52$;a|K4+vY*yMNe}oIM^?8?ro=Hq|B`-dduD~(U2age5Lu_Tu~h5; zl(a9_@lRR#*B1ZA@#~uQD-h<}K9TCG5Ok=no`^H)%-?(Ty)Hig$>n%xgb~9E>^c5{ z$)(K`wSroKaNFJJ_OYZbJZ3sK2CFR{TADcA2zGc|_#3jkuxzoYkPa}yON86F`qAmfzN!0$XLX7X8d4j5ao~9 zbWJH6vC3#CgZ;&1FE@ZxLNZ2NUUR# z6Sd`N#P}%ZO1;^D(ZolZXaw*(f0Ckdujn=n|Io(w8W*nBFRdr=i?AX}9FQ8=vAX>4LUdu9EsDA2JPlj&c+ zdK=3*{_-@MukvxcGOZbJC5GTu^FNNCx)xRCuvTbG&Er7%CzukZ&F0&V2IWzK*>H)y3Jh{3i537nkWH-)OP+B zg^X;22}#2Xf0etzpF7EwnX5fQS1FT*w6-)%y*-Ux$~|)HNoiCRtmI_>_BmWDjZJKc&p17CM8gLB2?Dtd zt=F3Es&4nic=ao3GGZyf8I7(xG3gdJo`!kzdiIOGUQJQdEpzwBDL0Tbs{wFqk`%GPZIwg{!N7-4vsDnaJ z!-pNj$=T)&g;9MW^cJ%XOfaCbWTtvNNB!IRW22C|jH+gzMgIDAUP&1C|Atk|nQyv@ zg^xHPJ#Bkm&u=-nWdDI{KpAk-e3!X9m_m2w_*?eAU8+Md>29c{pbKlTXt7^)`gMBe z2hNRkWUM8VsN2Igbexp+kABH_vU;R3sU>L`D07rW-mM*INeE8cVw@sAE5q1LQ3=+` zsi$f)@`0WJ^w+9MO=0MttHL&K-Oi5>H%u#6?vJH6vaaLS#WJq!aXzm!8?-5e?QYcl zZ`Va4Qg*N^^y#IdLu@vly}BS5*&Wor)We=4H4~<|iz1axKcy^$jpovoD!m*vi~wZ6 zC#&1FXT$&$zmc4&y^*9#qmi%*?tyR;eNU#UtudEMCQxHLzG%e(-IYn3EBR?}?LHe^ zo^QBeuxX5q*MqGCQm=u^fR|fD0v71nr)wSiFYyc&_pkGX3HLt5S7O+o{Dd2Ul&1UF z!dDDX0bCAi*=t*0VUd0vP?0VFp@GSwQsIPquVHg;hj&v=^QN)Vn9Ho z$Y_e$c8`lP+5l7cDYW$8|+*iaF$NLfW-g|S43b2FZLrm@Tji1$gRng;hC|!*0 zf6Aegv8BuYD)}BcN@jhL9oFrB$py&PnoVG~Jbm?5pwJA(Zpq$IJf1CF$C|5%xfgWZ zmEQ7vfEty(>^{FkuStwgcs%#CTdA-aNj9+L{i^~I!>JDQ+JMT79Ard9X}RXg*12^j znLnVTb0XTWLBrM|aAbGKuEO+q50Ej&=CudP#KjlfyM2~0-BUKRktAM9T?( z;PmyH^&I_E@Q2`QN92E5{%i8fMa><2NXr(tNZj#MWdnj=ANJv!~_fyZpcNtz&si?j|tDsr@+y zZw)gN;Zm{~rJ2Wp*uR*VY2W2>=HBQuy6FD0)=VkTjJK~$OCd&JM~_sla(r9OrCpz$ zV}b0Rx#vz>W-&GpmirZ}yyhN``R6ao+Gk9uuxQhDQMI^dqtNrsMdshjmWKSI?DvHI zu}w{UbJ4#?|kTx#9ZYpNPm+L24r&TA3_e* z_eYp9-B_6W1?5*A;B*SVV2f?VDN-)dlQ_P5SN)N$1)?HMYj{nBN~3(=sXVV8c^RU1 zzM}ct!Loj$ve;W_a(zL$lKWtgpHjAaF!$v6OdTS7SA`GNU9 z4}~V#|KwzekRPA@VO5H;C4a7zQM_6(8&)dVEK2l+xRIE2oJW1u3CL8vLEJbI|6M!L zVOu|Oi5xISnngTIKR8v%Y7~G5en6^8UJkRUBVaG*n|mfyO>tIOz5*3Pszj=5JcBke zX&=ZZKR;*A_$}CBfCV?kGRw>Y8 zYBnC6gG>>B3fPmqe$#E_v0*7V;N&PksnpGjep~{bn?}>VhtWWc-_F;2(!)2Ayc0{P)(}MU zskTndes3PyFTH0c0lZFt3Lt!Y3!F@%I^F=-yUPtuB^>@)Z579*x-?zei`Dut$k=A8 zl4MLx113s_P+DKWS_SCGPnsK^rTDt74;<-vbsZA`mE7EeeyTY)$qg^3f+!IS9&58Q_PUnUz`jloD{lR z9xBLwJ8MqlnXOF)^GmK@0#fq&*}<>5yk%RedrUzEw*#lb5J&iwT>j5x*g#5Jj$@K; z9S!z9>cyA+zEE$y(dNpWmg#8gm!;P@0}QtffN>9hej1TdYPYstt8Iz#2V)-C=2B_< zXqE74<+1dO20#cJF*;L7T6s(Lpu1Xe_?fEeS@iA$u?Enbm&!cd5H><(I$`RyCUpQ; z4JG-OW+^Eu0YrWDiCEodmz5p#2+nHW}&8*?7 z{xy(RN!u3c_`DYjXne0>UP+S|<7ODhM*E}j0yfF{`DXNUw5uVK+gR-qrr4#LduVEk zk$H3IV98pCHWr4-U}+0AL^wspKQ3F(scyyEjI%F6*z(;w3DlZ#nTi-bQfF{MPoWuT z&;+CE-&AJKJmASY9NjaqZIQT1{Qs>AC_gC0+V}h$%oNqHnqHn~q}L}dLKu1a3|bP~ zlwmjy+dKZMKKmSAbnJ2606C9h6i6<(efc2(2DCQtFHU@d|J4i06X#C1E z2BIl@aD2U(T*6_j^nu&K39&yIO>Kx13iAK4FrVDUDskG;w`_*0tkv0-RJbdaU0q}l zw*c>JR14mO0Bw42ugBtoY(dLdrDS5QBS_~+_FM}A*hK7~c7B-o{cFLSZ3KXpk##AU zONlJ!6RBCfGCmT<>GoL5)8VOa59GTeP~CElwg-M?KCT z8vMR&(q>7|`kru-@ys>atVbR>Mc|7NXs3>dkD9=*$Oa*+y9ZiSrZFIOIhr)uabtLu z0aOiZO${A;2PH#nfF`j1Q1#H-kKk}q?WNgL6 zr@D{4CCHA|3~65yh~WnJs;(vPi(H~wqo6YNM?OzTGtZv9t`o8@pN$%BIDP%2v$gw? zsYJ|40Snyq@?8euS(BG7FLAYdfYpTWo%hYk{!HeBw+{r+nq`-X(h(#GQ_4-uMx2T- zz$Nx z&A}2-q5Ceeod+O!F=4~x3yv!|LUJ+ zl%M(1=xq%MMbED7Uz*|Np$?g@i_?hCvhA~KFnp}HNNXLe+Z|{T9}*&A%*s?5FS$OC z=aJa_9VuBe)|1A%p_3+k0&?KyBT?#>xbRQxK3l4N*k6b<*Wwl(l*>PB2m`e5Qj2d! zd$DfQi$ioWF?XWXX5~liF7)A8R?y$EI~8VsYvEG5CC4iBP{Ju9l1&jpIq9EbjZg--Q}e9F1gwP0WpMoWY4GacqjPh;YTh~LH+Qbt<%d8#}y zjv1KCtHswIa52iaM&x2qN|C@-iLZ(O`1RX=Wu3Lnnl_<<)C*e1rRMQ@f~^tN+=GZ| z;d8-b}3`AEP8f?rhItgfh_k>1q_x{B__6zG&&?GAy^jOppdz93SJFrB4 zEzf3ktoC`vlx_vuiSgyTMbnkO*l2N-Yx>EzDkV)*FiFEo0rqY!kN@p5i-J^HJCWB& zC2gGNs|Pz64%$F#Plf8YAMe(^)_vN;>3iqq+c$on`96P+jYqSyxf8amb% z&eNpZWwRq<`CtO5{LQmxKRiS=|C)=$ZRjGY$x6;*+k5*hEVm837G?b@9c*=4-%ADC z!L6-s8~fjsO%qkDXUHZi`0)?_ll$uBBQJu|!Y{3BEPmvC=YMiMP#^Ozw7mLUv75&9 zxVzP2-DT_BPmZpAK2EcYYN^B_F1E?RA>$c~WhzfqFolzAfPQ8Ix>PIN`PY+R&!EKh zexor1mxnD$avqd+{XyMW9NAmtzf&ec&*)HY#4+y1tW8XS4*~Y@p#a#_=YgSK##PLB ztGwZE?uuVI)cvRmV#5pk@-NX9hVqmgv0*)6R(Fc0g&TSrRz`N6i8e3$E$Za1GY zZ!Wn_cR~eUlb-0|ny&U7adFr@wp#)Z#GQ zhqD^nU>jKflRK@Rx@NrkKGk#l0u=oA5V`3HR$5awoQ#~T?0s9Ax*8# zaBYowdM})%8U?HQG&{L4C;7^EXB+c0U!+VPLf|mu!^K+>=;h!H$y{|e^; zzIKbw@`htb2TxD`OHVufLH$p^f}E*M_4tExPdQfZI4%It1B40~8a>?f+WaU?y0nwq z0ZRF-2qhIBgqE0xHHukzv`FmuuatGjIn@^<08rOJDTZ30wbN%|a}p*j#!EL^t+0OZeYV$w7~%-0F&>M zePqr^uSuMp%1U>XYfr^Ir3lJW=NtgscTPg)xk>LVGG5k=4pmQ??u$*56p21E$MrAl z>seGf`;+$J^gfPk!cjH9tZM{TMxTjkf&>iqla^K)GJfbnpmJ^W(BB-xIvqe=OgW&OzgLq8gSQH%i>=>m@qbtvX#rON$BZO=dBDlH01{Azpginr134buZbcL z$D7_M?;1aiVZtOn8uN%s-#j4P^!qiWAoUuR29(+qMO3gRx%~ghdFv4xu_(~n5h1#1 z(`pkIM&5%|T2uXKLd@l*#vg>*pD2KwRKH&}l60@8!?i(5aaf z(XOU=W&g`z!+)`1p$(Abxj5PfS~LXL25oiOcmJo*4$PowPY(O$G^|vU`Z%)lf zf$r02#mhSdF@8HgZ~YeJ1p?)kkzN>?mIyI$DqwMoZYz1rg7q9y;*GfHQy_AyqYQF| zp4xLcb7eDH8VH3ArJ)-NA<#+CJ)mOds%@3-P+fk;%`jo_C@pFAf+l=iP4W^yfVc{x zYc>4-42Mj|kTvKw(Ji#5k?bG!wd~Y6G*vb+B%)2$ZhyO&5Mz}!JOi8f%Qo!7pmj=|p03YU%oiEDRXk_*_k*2@EwURx! z0t^8Lso17tHtes9rgf{lyMyhFLt}aL&T?p)vT`0RF@9le`TqEwf*ysM2*D%$@3)$5 zr#=(F0hT_YVeutb$=*44Y7nqa9CY7b<>1;b`NtRx*-IMQwKut#iSvv=PC_N~yw0*z z|8<_uj$`STg7WGR6w9`gT6JHq{h*TrTZ~J3?ZXN7*vJLlpI=Acs~^+A1E)E35;?B- z&mlS$(6fuTbwBJLOv`}==GUArEiKsVv_u(b#+McZXLkC>(t&{6(;?ny+ zwgc0|+@#h#lZ9|r^Z!9k^F-(H9Es$3BneRT-(|Srk5dx*Su9bisF5L`cF`qcUpxc? zSs}zni4j9|7wr%or)cfQNC9Ags(&Td^%OlL2cJLIkzfN2AVNuBn1nB}C37sO@wNXF zTDx`SMXE^eyi(Zlqw(MQfV<5oZ&5_90ph-Rc-nJ|);BjmqXwVgaQ?O$^8|+I*(9-a zVgZWSzmUSci8U+?2|DzEbmA^%hOgGhC?!$Y%QZzHh7-65e?hJUdRRqNkh+IKh281y0Ce}lbGkg z+%7JVkZ+ajqTwH{3RkM$^ri&F2aN2Jzk(hb( zfT)UiQx;qkzhHDWTHT4aYdMSu4^}NLxN-5zYL}RBIQE-b*`cUHZkl3D{FUt&Yxn~# z1=}9bgEbmItwGbGx_Q~QT`nPZsqyhMtISY7C8f9?G!ssSx*m9n4a{jA$-HHF{$~Bg z52$`Hr@>UP8;66AG`ca)ac|tJvB3tmL5*v+g{#@D2=gMcwSCL2oN|FmXo?IWeW<$% z`eDnSqL}nzo^R4Ztc0&wv|7 zd<5c(S*TY(b$mn+zoJ(wb*+DqFT$5&@X4tLFc0n zZip$h@!SPk9c7f&e>=j83Zk8Oc<4DyRe8rgz-?y}?fNC>TR&8+k@0QpaL=-r#yqYi zG_gey1D5<(G65G~irv2y+jGSp2x%2g=icrIszmo4g5ejVL4UD*=i*|i3HJ`~MV zn4$9OFj8ujpLxN}j{xzen<-6k;QSrqhRY!$yBu*j@o-gML5%HBF(*P&yK4m?)6KSJorx}6We1n-Ax;YQ+Jss_!16X;0rRj| z7g$i=ZCNo(KR)l;_dTPsGr3+ezefFSVYUV(YcWY*0qDiJPbl55)x}tMm=CS4!9y z^Cs?)$_jLZGUl?Wd)v8IA6xQf94IS=NkLLpD zPiENLHj@T726YM25(uZ2g^GLhFPew@vZ+{h=-}e`gmegV9T<1VlIj^Rv=4D{!$s$Z11GvA~zPd`vo+@IL3 zrk%MX$XY+7z29yL3ko;&tamSDt37pm?Pl3=xniQE1x^Zv2j!;)N;AFraOz^Y3T$_E zHUfd+50B(KzKOUi541_0nAo($Sjt)TJ(k_6Sil|g${cxhwakPG>$$>VG!=CVIE z`uaKH(^6n9A}r1r82A)qdM@SVVmplf**F5coTw;o}2;9!ti0Q`=55H=i2wMp(SVTT~8I@PJ##>4%imx|1nCR=7Sczc!8*_+-DrA z#7q{~dYCJ_IT}0c0h(7cz}whto?|EMJiE#bn4kL%J8NPJ3^{DKU-L>q8+7O(9JhBC zwE5AGMoDhjdiTdsYAd9oRj{h|-rAT{I>@Ag-Jir|)s&#=Jxoera%ouLrxb4?*?ZMk zK*WU}$2hLB5S0tBGgm_uf0p2$2nWFJab~V%6t^3i^@^R(i3tVBAezVOkuJ;UP3ab= z44F0vzDAk*Q|_HekLpj0cb+_nEejd}%f-0jCZWB+(sf?%h20t3Te*jA)o;fEGmbrK zF@b#pA%$~CG`_vgrxl=$Gws`?;sJTp18}kgiNQ zwk&NbFdUQXJgR$MYh=9P*)khKe@uLJ`V1oZ!(+YYl@)YjQ)5SsPvL5y(%%dYQWtq* z;_5gKK%^0Bl&GLoy(7AudQ;D#qcd~IUvp|lx%`@U=#~W9W(x6JS0mJ3eO5=)e~PY0 zk1aEBF75QnnOtgt4N5231}cHjzff&*@2{Geh=mmn>iogb3>9DC#NTyRMfpwRE@aFm zAZ2w{kS|UQTI=>CD{a_Hrc^Op>Q_cDKIOIp4hA(K*UVAFwxwpt$pqc?4h*p&6SZLBcmVX*X=+R1zuiShW{y76XtuVCz=I?Rd2B<@uPia z&buSnhB;P{tql-Df2Rh}D?q0N(sRMCBZ^{o4nIrJv_*d2%+M%kuW*wOM3xh>6!CwhS+qm?_u5}f}S z4{L5kHJjBU{BrYBqH4EYR{u0_`(wgkndK_-4Agpk+iRELAoQLm@^e!KxeW|$>h(H| z6a%HEg;-Tzo8H^?FkQEV!)TyCE-&lydQsqC*|*@Vf3B}ciMYBOk7ddF%q7`~z^<~* zzK%sHydxt87KU?JF1kTrAijb~ci4~qdt@6t#0+ifKwjp76Bmy=DvZ^Ot?6V=DJ5Z; z0OGaa7EQY{U*H^JR>Fg(qIsyihTlmslXZ^%WAwum0lS8EapJ!#0s*3O{s&PAf{_Eu zn-a|}9dDtEem|3SBV2PYQL4Zit!s|(J$J-VyE{eDczhI0)SGT=DzUIgDwjw2LIONF z;vwr|E^yH1?iNJ(b`!_y=$EZEnr45)#!lyLh`S$*GNNj^S zvneCDBf4do*@)Q8g=g-eJ>qa#N|hL=#GR^}NQ}PpRDLw&g$4Vr!~n4cddGF9wy~lq3|5ZGXX#4>5dC=hu5b z-g&sDk~2r0GoQN@vrk$5H-dFZV$+kKSM)X~eavBe9;8gaz4*l3K|0chkS>#DKt-MH zxK-NSwR2b7-?M77{@LTlZW52sUU`RgfJVc>D!nXvaN2Se_x*1%xXQQT(0I-J&QDhz zd7&G}6+x~<{qtuyL-U3Fh+KV1@sx^&H&0>X7a`~+35feUI4(cV>h0R{8gzGBb&nM} zT$Dxh+-nI!HId0tn_T9fjI>dN953o%;o$F$ko=50Z~qcoV()E{`F~8AYyH~Fq^%5+ z?x^puDoWd_)p4(;`cxIu=TDDVTe#+b3U$PJ1VLZDCt8|paA|bLf51SLo7}_Sil^8W zfS`u5uq#3XgCp~+QBap2Jhc*dn1|s%!jT#wStl`Xg|cq0@gS2l;p1(QUfJD4I=o!L zhWj{~g!_*Ssu_4Gs)b1lM4q6uuIWke2UyRGW6H4~ZtW7vz+K!6oG$OPz?CbCGH}iu zw}UON87jq^&JDz?%mt+pMlIgI>#6oZ_~o=wL2V7rA>boT;$^;<-FvazG*DfgTPR%JgG?O!Qcj(x}f%!G`5Z)Y$S?%-yl2s1T7HJ0WR&T+9@ z?+xnSlN5q2Di!*%eL8mNU@oYB2RDPGCziQ^53eZqIu4<`>TAa#Bmf;)GdN=n#Y0Eh z&6BxfWps*xVtsniwztSJ@@^yO_n{Mwyk5})`S8+x^!G<_g)#33D~ly{>{P8<1nR&~ zGc#RW9c$m0QRMH&yQWz;nt@CY=X_ZGPBZ-qBq6R+=fpy&x%j@5!q40%v5JqUKZGS^ zs?QXR7joU}lk4N?Gha3UWe~*m*)DcUfa<5%>l>!5->_K`7I{JLln?kPSX#)M67Qdj zi{)7Xf#cR9!lYH-%^LqL71qO~qXD#xuvAl^sTbom4chaTv6Q z=b2PwN!Rh&5kv01bIaXCO45#~8V3#A6k{~lKW|>u8B&)8PR^^OD?%WDac!4;!jx6c z>NBJ+Gzorj&=MW&(SQ)oB*g!DMk7?L>oWb_{7z4@sT#M%FOD+gQq)y)AxVQv=#CFe zW?kl2+Sc7MOLM!L&lN&am+X6v78`1S()6=!VB5bIUgS{oiIeCmjvrnGF{C*3pOgXm zmB`e#WGPPcMw~ot#%(J1Jy7sn7DsCIPX5q>sA&3I&{yrKPTTrNqJAh+j8iTS|Mg#8 zEa;tF5jQRa046CKYk}BesFn?+iTOTa9;?X^6Sf$yYV0{p@Uh$rIB4OFqvD z<>JAb8uN3yAT?q5o1O!@g$o?I#Mv&r(7N6Aph&KHapsr#rl`oYQJ>mdx`r~=jj{iJ zg#Ggp*L?W~Gk>7HG1277O_H1y&_!}ZF0V{2^*ZBrUicMPM?7WjM6arJJ(EZg>!qs zXn3N^AflHc32FSwtIrLN8(fs3^%=V1Rc~i-!Oc2jlO|)MzGt|)8U`FzFZSB3pgA#A z75XY+U4EgJ$STlfhK*ikg6V$v*PQJyO-V}n&aFFb10%OCi-n`pz>MoR!CCfz7i?MZ z-d}T7EhLRS#WtpZ*o2s{nv8Mv#N+uc2I}@%esz_dH=v$3xB`TXjGy><8@KAW`VH1{ zt|{K*P6CNqQ=}_48qpTc*Ln+{_Q zW(P-5gLLm~j^+g>ZskS+&c>|%`H2CE=K&omrT(@jG^^hhfmiWcDHvxjTh9z_h??8& zR^JjL6kd%=^b9QLYv=rjY4zJtl=JyCkrDllQ0u5QnNO79I8~NQkLJ?~71pQ%8Q`0{gHl^`Auq^LgLTd~y zxF&X-AE^5ARa;u@5rAOhF(B{~FPB!GVl`clsqnGPj;yUkSzvIxDg4S%nOA zF{`lbelA-`*^PpExca zHCFmb?PEpGh>Y@uZ9S+CeCvjQG&BH*DQc!Dqo=F(8JhCnTXtvnus1zZmq4@39Jovw zNnAr-Ejc%_W9*#N3GW#OzywA0U&r>|oD%@=;7VQ#wNL1EM7`Oskp=zjcIWpi-%K^0 zFH@X&buRvALC68S)jE^HWv;1v=$7!(rL2789Qhf@BG}4I(31ttWa9bLwxKD@+cVL^ zLdQ)-0g7x#T2FmfJ8-fR)pM%1H@4;7Pnhxug?z#Ca;eBdmU|emAFeTE%zMDu0UaD^ z8B{FvUaFy$X{KE@7l;J>TV0qx^Iqk^?|<|5KReZV*y|$xC;A_zG|HyuRJnm@mtBgHa3{ z`$PTV-sng!XqJ0Ex3PjqL6a%nJnXiOwZZhAm}kZoaf58=p?=-k#%nm5B$Oy-)Gnd1 zWS!BN;ND)oE~PNBgLBLu424S@&oJu0PeEb{86s)fM2YgWLzKht0uoJLqZqL1cOQCrfOlPc9}ZmzS(!X(ZNRD1OQ?RT zZYY88T`$VMN9D_PtQ;o8=}cObQIV{P%6U^HmSl+ech$Bnj{Z;stDmK7I2M^oBYVmQ zI;Tdb6(D8&v9AX=@LvDp$-jNh%D1lFBk1-Cuy`b)w0zI7)Ct)@8*<;@RCEQ*OXa&5 zPy~e1Po?H86Igq6G^4^P<3Mc*8d0)bF6F;o4`#S~f=Kel+`kh4RT|)}HWm zb8C)_c}7X&dDk{aw#_q*y&IxDQf|=hjsWGuohhErdz@r*;R7xvAM|DycK<8WDZnE~ z?uYcUx_++=65YeSgZBc-eGBzkwOPFDBJ6SfPT@b|A1j0;%u4~7@n2f7V>j{SM_zBt z)9mK3ltETD$M3i&FwtrpK#|kH@ zjS$%xX<}MES^r0O;+j7YYkk`Tnn`Pbevskj+t+rNYruks*whBbM@o_*(2-pA7`(`> z2f14T8OIe4v|OA>;BO^K%9M&WeLf5*EsLRx;Q^SvpoWHfU-{VeUJBRmLfv}WCB>r$ zXUOXxk`4%f_3J$>!D>2nyafAfUwSvoGqO`=99_OjtmAT%KEsOZQhOJg%Iais8}Oq@r_A}pO%N1A$P0@8 zD#W&Bg8)~*F)givZ$D(ljytY;@*$|aOla1 z`AN}ggHQ@TZ0YcD!)`vu{dXP~9sAJz?9)PZ@VY44mW-|+y&Pu92||sRM};L=eJrxu z3C5AwwQi#g-8#bPAyMr?`EM-w>flgMi<^Bn*KFFi#Kzr^FBcEinf=<|-?@#OA)~i> zzwgxunn!#+IRcoHWDhZNGN2yAp$l~c#H|}!eynyKM|`G~rae1Km^Ch3CQ`}Hk^o3| zq>mrD@$f|ur03Us%9+&nX0)4&S;<3uI)Bj3xpjsc6CYS=*8;2C-U8a?Tz#ASR&&RV zk9@M_Szrb8$FUxg9t{s3C63d>y4ZfYpAd5aP`*h%qe+d%kHE%n8oZbopxnRSXw?&N zxxYJTRt`ck?_m(&<9e1bEH^NMg5)|qEdiXI&pq_{{>ImiVP~J*j_CX?k?1V546|VB zN0Sqk`6Z!Yl%s2GerIuH6ym&{;>-O4+7h^8xo5X19~+?xF9(Sxq}0nKwT5 zki{`zYF^p$nxH*fHD~HrZol@BWxWKU$7pE$`l8Sc)+yHd4g_*=T4VZ}N!^UBxUPmw zZy^hB7G)Q;u^hCPDX$x!>BR7;LSKAV!%*u+qBz|Hc!z0@C?J2grKF_muA z=j|~%dzOhS)6M?K*|wIm^GGR#h!GaXCR0<6ib|6itrgrm$mzI0MqP#ls>UD45U+T@ zB}LbLhMLo9JCYCAfB}8gp%nAH^))x?!5%BqNGTPH#J-Neqd(KtvQgb2^;X|KH2!lF zmT|G=nKw8Q%{a_jPG~JE#HRynrX=r}e z>pDP&MRH^A5pll@fjd^X{NAtnxsOSq1~!R?nPrt*PlRqtHQIS8I}$NEkatHDjW?NZ zr10V4@U&-p?EFNy9Tmj~Rl!L7;bF01PX+6EwztzE?MO2L!_BllZMhF*XRznN@b4e| zp4@%eV^1PVnSjKx(}p^n)^D?AE;W;lfu&oNYmEFek_5Og#siU|;!oH5jr3Ec!4g8_ zs8Z@G#l3NY0q=9p?)FET8?%2m19hOT&VEZ;``EP+8bwg1`imdDmqT45-~?-K?LKs- z%^Hv=)ZEyZJ!_9YjrS$%H@$KIalTurVdx5C7u6cz4>*k^yH8zlPkRM6g=?lBkHZ}I zrXFhft+PyoLG=#{6l!(Ay?LwA+j%|JQJqR|Zc8k2OTrJUm99)#4=dxE-++qZ%cg=) z9^;MrQ9B}3&LIhsU7M53FwRtf%FHWndEQBR^FDzNECVhF(@y{4hSWdUOl|^mf7O>= z{!OFi(^xtB9^`<$UrBGqTVQ$COaD{&5W%*B6Yssf*|onhP5dt`%qIp7TCy>@@jKzaiN3t8q{+uwhYh(SlrIoLh+`P9bW9uGtU*ZeEsDwtkS?$xw zNPzOd>K&>MKH>|;JnL2nUNb&V@e2 z-K;eN%c}S~YD11|FZYud#$6+_S3qll(QX}&u!jR|6)l&b>EVTO_IzHy22N$#U>-Z8 zj&b3-<}&ZlEX)BP($kN`xIvIG7UA91TA;JS%fL9@J;>VIPPiQW`I6p~8MrHBK5jbj zPe@I<3;SsL>A~=wPN2YLVPCKGuWQA(AR0JO|BTz)%mu(*2=%09?|Q2RQ1$f0k|&Hn z$oBa-{_6~T#~`m4*$|NDMW^}pK8ZpdNwf<%0LKz4xJFgxplK5hvT?)S%#z;A&g(ts z8KWD@^xY?Ic9B;tQ=o(DU0+;|n+c$Fc=NqYMT} zb8$3?rAtZipPp+`pAZ{W_Pva!xX!sV*w><~H09S4Og4XL~;TsiMIV zR|;6j30DJkU29_i%N2OklVgtfw3pGB1h;K?{5$*qr|>u`B(HsJ!_Dcgc^l4jc0vV~ z@zlUSZZ?iXl4KI|`-EFbV-mHrOD%qjVTJXLy2WMo+nY1xDB%}`a*vtXgXp9k30Dn; z)H(gLRiUApX`{p5rbI9~@c_dB2Zi@lOXKecl4!ijTDQTJH{(C`H4*}&3zj_jepydb zCr)JMbVT1302!!}qzp@+_nbcfxku5F7GQ)!N3b=YB6o^=`^|MBPlc8=%tuk7a(X8MEl#8j5vwfa8qnDFAS=Qo2i*pvt5uBBNwy$WTYRml*%kId#u zM9(V>o+^U0DIVKH;+qNUEhvC*GBhi%(09kC8UbVmUP!+7ttZ2hCx^uK)SWka=(K@J zd6D_YBsH?i*NeoHxs>LKO|X462%yNdc|u<|vb5)?{xW--VmCTA{ z^|tl)V>g0qeMzcR4q)B=9C27Ub|ZSs0}Mg|F_l+neDk;@z`1y&pswD63TWPP)i-4> zQ=K)A)XtR2NMng#c2wB6(Y-#(J$TCBzE7}>{29L6-s~+dAXog*r4~0AHz*AwC~9b3 zc>YV@pUgsyKim4t#Q1*-4Oa?=1t^^ORE>3y5}CZ76Bl@EmBG+X9VehM(*qq(rNrN$ z(ZL0&`KggX#bjtxLT`s$iM(%K?!J0LQ5%L!=DW)&R)1=N@c`6XR z=rUEt;Bjtk;oaY$Dc!d+NH}-YK1O?FAK*X7|Bf3hH65H9j!>j01o~wX>LT`D$6PSc zjchE!EAI@v49^@P40Ne4VsgDEIXYFGz>epGeSihNn?RFx!3Ol0a!S{6!J$+shgoel{fRs!&(VKsg?xG@FDr=4#nOp0Gw zXL?yD7S>mrO;@db1vi}2MO>GQ2bAI;E*}{>JlL`?I-b8_ED8ROD(eyh*PHK)h?vap z1vOR;G3C*leqVSsoHzDyyybJGSP+HF%~;`~RyH-WJUYY$S&eT*HjHxro1#lGTx%d& z#9ii7qbE8o2sAK^@^y7bj>qJ2(~e?D5ZZdID4gKoQ0SG@^@XMOSRLdLo-ER>+rsi@ zO263+f;)A{>O0=Q^!Q#ohxe=T0;}9+QAtmpz6mKFp>71-$T=))%Glt0QBd*Mp!9Y~ z`mqDre)!u6O2R6U@+K1&p(trrYW_&W=PgSgOar~cN_YC`5Qw$dDsKt22Jx%0Xw&?0 zoWVX8I%5fBR~d|66PArI7X!AERz?(vngi|ln^yrm)4^3nhB=IxNJ3WoS)j0eKd`Jd zK^bEp8*nQH&qqwW2{jwIL*w5)5~OSY@>b%b5Jbp!+!YaV-nvxK_dY}7r4zTr^WuyE4H6YMAoGWv6S(7gUz<6@6;0X5)ig{_J(8X+vhGh*Mm=7rgN1~7LQ>XV5 zgfg(|t!c9mGS&TBigBcnDn1_X1(80mA9)ionAQ|bHU zL4czuoR%@_Uj9IJvK}2EuWOkSKOU6pvpn4gcm0-Jw=DK+8Y5o|?26J1uaC$=T*u~yt?qoil#7={shgbTgB)iI(V~@}u;Z)#iZ_Uc}Rag&{udwFzROi!|n$ zI5Dw4Xq2e7{8qjOmWONIif*5bD`t#o&D2Gdh*s7YOc<{Hj5@rMlfWCEZ-0yAE)rip zv2FIcc`ybgBBHh^j=x@!X(0c<_Eu{X8;+bR!hmLW;DEX@G8?IMwKv3 z%DH6ErO?I3XlgbN|2ON~HY1|UG^5wMYSaLK0Z3|(XUlnl*9<3K?1ZRtf z*B;vq1ED%8rYf}2=hxbFFu)3524}8k%iP*qqfK`FBhf9WLu!$=ICS>W{b9Z_A+6x% zG)8#0biY41!0S@6pEQWnKG3%aN^6CFPsyXXHNkqV(Gr0s;?h8GIV2zfp92n8cTm&E^ z&q$ANwYHTR$TKn)KB~&w?zc*mPtS9+v0gU1N^VL1an)?;SMgHtr;)2f6msZy{Lfc* z|5G@YfpyUla^&4ZOzR!=(DOyh*RwhcYRM^0W4958-Gr>fa=C=rNPK}W@H0$39+mr= z*5GUofd-{f$~d}(LX;$p_!%2Bclje`Osy$BnEHy_<@qQ#Gl%|i4ojDSh6EQftKQ}c z*aiblwxr_XkFKQ`YuFz7yZjwFai%aT_{q#6^-ZQ65a(&GD|jN2Dd z`WX!zJgSE&Ux;ZMN_R1F`YS#Xh$bTJG8^96P}2C~9n<28v?Ku-J^f;d#~$a# zqt!3txLJ>%>mJh(>918%vNpMo1~k8?-teOvFih9_Yh%#u94VR=Ef-nG;CY1AUM~n% zR)J8C3x|=e0{Da?8$HPWf2QfCCv&d50*A`oeWV7-OOTg&f*acfe6l*!o+2dhf}c0c zRyq^p29lZACP*$lnL{$I%%q+LjVxs=|D&=tIPM5*l{T8&G_c2>kF@20DPQ-Fy(3eI z5p$24bFZ9EVM#P$pVsH+>qhD}98=E0^4ifL>#J5{pc$T;m#-d9` zs2pwnCv%2NZcC7*nCPyD+BYoU?RI!wx?P^TmB6X*QLd&7BU4&FO|Q2BpIL$T#$Oi-=@|mx!K2fOPZcO_0UB#Pfd& z)o%h0Abpm5X(9XDrFf)A97`9>I}ae_&%|rQMApf-adT$YW5gsQkMtAOG{0ZI*KBAyK?QECqK|Hw><0C)2o*cjxy)<70i*Gz5>~FsjTd+2K2HmqT4pqs1nKqdjj z{?d5kVkC&L^4pU;^8;+nDagdwIiquCxWWVWee}6c$kX6-@)wR20)51 z1ByJ)Z#niwlI{9XjVP%ZMU+J{QF(Ak-F$WcGt9UaHv|QhI79j78EI(79@|^u#zbs7 zA|Y)9FsuiDLRuD#%NNe?d$J$>m&<$fHiEo#Xh`HisO%LjJ40aSJ}+C}LAdUF6cG1b z0C(S*b)uevYOIJyFh^=7Du=M3NzAG;HchtMR5}N_BIlp+t*Eovs5glQ;*n39yNMWE z!5|Y(EE06q%GH}MA`05$;cAk5y1RY}cpo|OP*h$%D(Rk1uyC23M?C-U!&!4(4=B~P zGO(9}4}H_wym(oqcf3RQ64wE`AM|(O30j;@%U}|%4ExDg$3NoBCD@?L*HRFkMbiI- zo_hpF#8y=d>o0Q3&VS`|pq_WUMQb9KSz9uN>Cz7+{&e{oNKr@5R2;8RNe>L_g1*b; zPiobfU$A9$doEM28&f3&XXwscNAxII-4#K@x>2$Ld3>K0nn3b0(sMa%e2a#FJhrYw zuJs@k+W6D?faEe(mTl#H!lDHw;};&;SJi!F z$)I%an44Ts*649b$zf{!N3G@8n=maU{BOr#4$+CLnk!ZwRF4%DB0h!+kMR zJ~foc$^hJ zDqFGapQwZB>iT{^{{BPb3yu@j{~P}M>e3(<Of)=_9jgJ9uZF3&W;+B?sLXib^eeS!p_a!pgfHD(#-e^)XAzTDGOw{t z#jJ8rMt*ywq2BJra>d&v@2Ft!kF#8YWmp}SZW1>=1l_!)oVRsSSTl$V*;o-7rlYmO zqzMO9i`uF*JHTNO3&BVITho=+AYZVJ(O_bBPl6&9nkg+>yNDBSb&CgLF9npO&Pdvg z%ZKAL_vtP^@i3fUUxw~29|DqJv)j55L{GNib2H#`ZGjN2Zl?IegpynQGUf0T3-#L3 zi(9~42ZF5FDD9bW&Gd~I51q9WG}n(*I<=Nd;!(Nf;YjT~adb`kn~S)|gqS{k`f%Yn zwj!DeiqcdF5ppMzU$~Yd7C=T>-9!JX#2;pU@JP{$D=_296-$1RwtxF(4cv{!e@J2c zdnwFk8I3al5S>|p{@RvI*_ZVh1SLbiWYcaq<}Dc?=Nl8~h5!&_zr_s5l3_OAxSWOZ z@R=!@-s_feD$ljq6>8$Ml0O;v4Id9LW4zc1J=cHeOlKlMPVr2SGZibjMplwJ!!eLv znRes6Y8)VTdxlgD=6Pu)9#1#|JZmiLoeo*fm>iU}Zv#`(vJmQ3mV7W(Xah$6n4w2< zj%M)U*ezFO@M*52Mg{5shyLGIzjKa;E+gYy z^IQ#gsONwlAB6reCx43`6ZsN>$}PZ*!P;sW7khpEL|9OG4^z{Wl#KT?mhXfa*rxVi zZRHIZP`EXGzZ_8A!-Zew6YS{b-36x3*s9}4-IN1H8NlmDFzSTbsQg;t5%sl4Dn_(1 z!CM$IJ|Z{;FJUiRFclL7NP z-QuRC6!I>U&S%ziGDuw|P0s7XE*R55x2{}6C$Ye6f|iNFlC4A12PdcAo`izNexAc* z$U~fl34$YMdUz+(j8%a41|!Fz_B?MhnCF)a2A~=lHkeh^46W9uhk^k80J_ic1Rz4m z1-AS9<7!`6;4;I`Z%iAW-0vwIoc4JWmLu6L8_nke0)6buTBNT?OzEbZre-B*#V*sl z!CB%(yP(6KYlw#p8uQmUwST9sS)wPvy%jf!Mba0`M3IM92E!v@vm_otzR~`@Vk=m? z6K`MJ*%E(yd@J7Qn>3Fk%GFawT>83qdVP)PWKt1s>1T~kuCu1OhtA;HJts%$tu(@> zpiIdVt~-?*j^)-0rSTGm&x^!C%)WdUYlNd2c;Qm!2%91rDSR_fH%B-p-bjxnl3}K@ zft8;R?3~_tT-(O!VK$al59}HocTVq;13r&xX;hg0OVYl#d|M86CGW=ggDuMheEF^@ z)oo?rSJ!X5VJ=-Y;5y zP*FW_^r2UG^;(zenp&qM34M%ksV*^hov+Fw(e(De)7x)hf#7K4#kaF_j1LSdfkWqD z-_jzHH$HPm=uz}$*YUoTOZ=10-jl%*{WvmMf=KUa$FlGkws_@3O) z$TK33+0=R`;OPt)_(fN0;kG>KX+!>tu6=vG1^!d8aA+m3tPJYQoCjT$TAyP2f6YH4 z16vm0mF>3g_1=nf3KroV>m6@JHFhw1r$EJ+3W2mfFS7@bZkBp(Bd6AJGmL$G|2|e-kq+siTSQ7l$7N~gepqU_0R@WI6<#>x6 z!P-|qv+exl4*QtyP%gokm|VJXGHH?8`-SjEht?8E`nh0(u$~cXNubiO6zX%L1DIr$ zgx#>5alFhAMCD>UT$Fb$w0&*gQIO>U945Z#j4JPrV35&e&5+kFg{9Z$jW`ESMhZtO zm|s`&UXKM>_#}f!RigQ}kgVeF*pI){IF^$P@RD>XkCl-6^$hiZCtjJ4poKl171k|A zR^Vc^P!m%0P!P3ie@)kIrP~}b7{i;&d!bU3ZRGXFVUk>b--V&Xm3U#0B${{h!qLm! zhww}U2^`!NAq%?BdvEOASa`3%-~ON!4qmx_!N72vtO&t|vQ$-rS(!^$`walV$hsq;74D~vW!;gYD|vymR0 zEz$*-g_XRXrvC3usZ%ST3UVRf0xP#&R>lYO28N0xu-@ zBULBdo};2@9b^l?NZTe+`rRDhhmTzb zi1JkZ(2KsS?f!%pn7M*sQ`X9lLmeP)dND?fk*1jgU+Mo8a^YIl^{JsoLchg$_?L78 z&r)z~uLe$J$uao_y4km}RDDStFp1wKDXo5)+%WVQ3VZxpzk$Ormq9RHY5CM+oW|Gn zo}M3o6JuK8^QiSmap>yD9gK?{FvD8nvN!$6H7gV#?CMOyCK*v`?bE-p)^n;N*A(5* zN##Tm^>#7{#NU5)YoeX^iwH9cp-N&~haN86|l`~uar-1#kjuvy+(Fmdf@ z!K{u}PBqXb6ku2SZKWFExvwrx>FCK`!$S#$u<{?;XK7KJjXd2Sm923)ZE434g9mqy zRZQLTZR4iD>8CCMb{3;_PN_FJyXS}CQL$ytT1rF0+Sf9>Geev|Ss+ovW z3M#Y62%i|_*oAbU6K0lQPj@^lW_}_7#zd6vssXPKMVirSC{(TlYq+%-a_PbwWekVo z)0*vWmov|kdM>rVE2+xLTlp%(*)keDe1rGCz8UUnkWd&}W2cE4E7bGGK=-#4tHp$% zHdV{_(+F++vPHQKx)YfzL9r!yclFIu13?wE%;i+5@6=Ch9DaC3#f+LuT?&J_+=TT! zkIP;D`d8AZ;CS1sKCFtE>uOqI!4!IZm2@Au8NQ9uFVvP9sA5Slqx*(>WSKaEd4&#==*(L4kQtY zEl>Dwv9yecfz83EEBxvc2PcC$DGq3$DSA|yhCPZCU3-2iPGsNOZ6l}YmHE{{T|XN@w*5FAGa=BG}zXGV*T2pG1z|JWkfxUovSYkhx7eoFow z#2#SV_VE3?9!E)M)NtQ!Ra`h&pSK=le#r=rv&X#|YGDtKd~|N`h8M1gmUequlcL$5 zB&rX*;OQ3_yRkLzEAT3~?|w@Qk*|&}k>iS(i>D3d3`h{q0P*2k0ocN_b=SP^|3i}r zoF+CF<$YMQ{7Z+3@EfnP`HJYxP_x%~>>;;?&4#Hb4$;G@S(t4^IW@w7Upif&e0ace z?({?b_5V}I3>@ROfnyp{w4pyN23b~|uY6h!!*CkOd>MMo+(@TGA`g^?@q?C<-*R9& zxPTHdxWV@jz<@ybr%A)@S3_^v>Sq>R?tDh1XoKM&Z~932)aHE8Bznlvx&iU=uxOD1 zwMLYd`$C5*@szQ8mv9sAlxiztrKOp~m_UqC``bjsgjqAL`h!qd$1Pth0ZA8*zd1xJn4aJ&gN zbdi}Tt8}*N;X+%36$-E(Og#}!)grD{ z^i(kAg9A>|ta*=D_BJv3EKeTc*@e;1rT6p9M6+A94oI^%al^og#|A$u&ypZd>&*gE zgD~bY4_?O00^xvrpl_tpw*dF;VD}*8EoN1ca@zgIH)=0PrXIE7>L%-Cbw4Nd2pfNb;8nHlS8Y$`bWyCw zVVQ`jbOS2{80I6!=}*}n6Tg#|>F*g&UD4PsX7Tb)76+u880?12OkKi)G`TAR?nhQ> za0&b4veRe7Ih|r>10&<>wJ|%Ny*w&cB<}nbs@bjbpJ6v^@YmwvrMa6k&pO!{?H(=% zmS}P3WaW2CqDw^$RfI-J<6%DhmoH0CFGe3~XjemV0@1QMpaypwf4P+aEQ9pQP+V}! zs}oe?IDR1P4ZKSQTe1)(W4i1*`G%Up2kdAJ0)oRY(VN{l_9&FqsxewNpY4*a@@6=) zc4`aV7!a3V*Eh*Lyt;y+rE{wy>{84;a5<)@ew`~qDES9SRiTqH9k z75|F3>NO`>g9w7FH|~@?3ri@y#`XaPw+_kev5NV-Yu!ZO%=RZJ6k_ML89@WakW&$Q zNPYS};$w-imc#p8^dEt^pZee6L7*bQUOC970Zz7um9Kdxzj|e)M$`C$@!{>+)@`oy zyY_zBJ&z;1Ja(Zup0l=Ge+n}L4xbNR#6v(}W4pO8@O&(@4v)WaGe_#WIjwtUHY=hoQT27h zuPTg!yi@0?$JF`=nb&0?y^`lWEFRdrReP~@V2_z=o@s_|J+|(5)P9E(ewiVt$qq12 zlVxVCp`M!t@6=4AN6@x`3J}WH0I>w*i>Vfw8`%XD<%3q8irF%D%fgwRjt3tNy*1r+ zp0Bk^Mn2qbS*<NW)H$R->csgHlRgkA-3;#yJ&`9pR;+>szf`D_A4^*%S$zYtFH=G?v4=ilAk}xhvAvr+WcoVdhs=?zx*BW&+7)kOn zK|Wu{@&@@DcinXjx0ZD;ng7>uR^qfWos@k8;y*Rd7Lp+K9--*9P;l`pq2hU{#dw&b zmKE9o2)aZC4q15#hF`=$#=yYtL>kfX5z1!MqQG_zraH)ud)?EW!VwqpSBJ z*kTF`0M6sm9IZicm4vXlU02DEKSpa=IGVNPjo%4&K`zx@*Tn8;{Jg34kAQ@HMekra z^CGpog09V=i7p*f?GsP}G{OMEFed1@%}1e(teIh*|EvbQ!zQ7L~J)W}N_dvCkfU5zw*^koSKqe3qImU*~RDdgGoX4}XN#Ni#pZ%v$#h zYOM6RhZYZeS1EcR6<58N6a7I# zX|B;Buhmtfa>H@3e_+}lVwsZAp2ERB-N0PLTARK;YOj<~c&Ve~R>KRFO$7H2BJ7il zmbvXP0{8&|LbKg#mz~>grnCh-uZCM&oVsfCD|s{qXR}Z+ajBiZJ9D_hwty|_iv9!kJ@&9uFw1M zdOctL#sY@#wpT9A5cxjcw-p)-ftf`>qkrS^py(JR7f$8{XE{dRy;&072gnPTtlg^m zcKw^e>`>X3$lcTZ`yT6+aqe-6BHo-`SYvbUGk3!r2`*U*OHNKgRjuDI*+y>=MONLG zxji3nxGpRU16&Wp9lH&ln@Sv|kc)H3XXt~}wqyRG%s=Zwzvh;_Y4axF>n9J@nuZ*1 z5$dW-7(t)%tSr8`So*60hzAwx)Kt%(t#tq zJt|mn*v(bV*I#{<#*X4)N`3($zRmNJ!O>c$7A}1c)vSCkXYa24iXwJv=GEsnWZ-de&M0m>vl`e#p?q-8&K+ES zbjwjvozyV~Nv>q>rmm>^i`=YFkih-2l+t~2GaDqbD=}!ua$Vl?<=|?^OqAQ>AswZ8 zQ&N1UM8cB|)dd%B8|&s8pqnXj@~#$jU(At?KRdUOx)$Z3S1Vgm`j4g_vY2<#{vZL` zRc={MkKf@rLkcb0HQwM|jZ4W+W&bxg-hGqPPUane&q?cXipfxv&YeC4-4j-b8QNP- zKy_MKB_nyX2AU@cx|^sQZYe?_@5T4Dez1A~k-#;k!^XLm!Th9MhRP<;O7Cl9jfX$s`5J;r$3f-1R^bZ_VKTVr-pA6&ts)`)x$1N3%Bq?`k2X*A-RrI z^sTVVi99++T1c_)!SIX#k{gD#92>~lowADv)*Ob|RZYa@(~2&8FZ{VJ)VguNFk)Ctv6lK>JwDkI4}&VUD2`I+ms8q$JHnuIrsC zfqpsJ1({5E8%}|LMg-T#LE@W63t$awMmfH#e{}g{!JB@0u#%0h%($CZg{*M35E*QKZb{iwf2z-%7CE;%xqs?&ob--F6|rsa)94iPg7Ml z+xJR)XNg}1S$;6e@Xda*S@6fsPxEe(i3*>)aII#MQvcys-6>u9 zQ@bI!6wO4gf=f+eRiP-M=}e6R_-cBUsGWm*>CB_GRyDs8wXohUWB^{MoT~Fm?^r z9KuKdPGaEdo}-59@{mq00bphjoj*(s6$qwfXC&Cf+(@)`cVMhS>Mw|6zfpwG>T^{@ ztQAX6o?KSS4?b%3eh_^2T6WHbYRI>JDl`9|B|rNWiZnFiI}Et;+ikqfiBD_>y z3=23GSs1ZoQd!AB+{-XL0X4Jm79n3AN^^1Q@ZGa9;I`{+;TRG(&S3>}uDoAq!)i0a zEohzT{Ak)Hj~ZhTuyV?akJ1}KEgRlJ3edSDm@QR?>4gxeGh20dMkpOO1t}J z-Bwae`se)U_^FwZQ#X-)04Eg{*f-0WQC49iLCkpP4{&uGkuY@(tB=gq&`U+1n+s>E zzPPvr`t>qFhubpX?)d(ER&JBN6!ukG9GrZgAKgD^cfj(DNcbP|u8Qai>AIvxPfEtZ zR}a^?qdMNyJ{V)fxw_9nzTcwn)CP*$ikCg}J=G|~HvlL?rmd5^sK2b?@8wS9Jgc6C zQ7w<6ZEHMA%)q`x3*s3Fk9Ai96BaS~uBCB|@R+hBDelz9h@0vn|EyIzQW*r=zHrlX zmVs%AQM#bCo^+=_{eO#YwMCNUI?oil_EimQHNkIo@Aldm`*L{?9SJM)q90JCNm>4= zr*4;(ecZVJl%gh=!*o!*BUa}{TAP?)FasRUEuypzGE9LtC@TwjnCc%@oWvGmJ*u>r zfvIj?muvo-KDQ;R7YywM7MK3RJ$$`xIhe_uLvG|5^lXB`6h!Q-Ur`!yS4*E~6=&DZ ziyMDM7DV@Wk-=_^iOF(2c7Jz%!b`+g?eJ#TB~y`#G}@8rAs5DgbtUr+E6{l9s=ylv zj|gOM76X~6kFY+X2`=az(Tf9~{y3n-5!khcUw}f^F*6rp^7Qw$YJJS>4}Z+x!^WbV zm7SFV(_tKV+OhPxC&&+0iJ+jZ`QM_U=EkLLf}}2$b7jm>ryHig)Mv_Xo%tM82q`<4 zxIEzV;UztD=FDV~W*ZoyLxyeEbDsOKLsm zBI|e}cuT~5qwD-GcxH?Zv1zWg0asmI z;zgTS!6gDTJ>qFkUOsnx0BH4t(ns)lTJS{xG zDI7@Q=lrs#j(_|*lCFG_44?&l0xVWZE8>I-i`&Zsbb>E7wRBS;9mnt27jl$zBo&D0 z#gS)>kU1(XIo5CNx$(4(4LPDt7Z4`FotYY@G+D?n%UOls#OI?wiCh(JFuf79h84D- z#(rFOF;1)FnVG31)>nw&|9IT$bPZYk7roTm{9Nl`c+&@?^8;% z8DO{Q(~mAasxx=dhN+r^aZiRMB`+KRzc*rqg{tQi)KsD|Mm9cKVSM||Arc4yke7n4 zZX)i#xYVlLF6;kFnzGPD@8&G^9Pwn38f5-R{Z zL{TUR3t?tdnM_;BYVw1xtT;2dEULn=J>F8*`*ZOSE}HumyKxp#F-1YmZD|&)UAW8T zdq!ff5cIfm3p$ps*~Xrv%sG1VDD(6ztpN`S)(`~`Yd!4BxWI7d2*iE~r~lFXPHDv= ztD?PTFI_xzt8Rn-IHDZ*Nqw z>%nDWAG4Slla=G@TrnJXu*3oNUc>VHNUdiv7eRkWu0(U{7sA%R@>dT(S%sGc*tM-Q za(NHXVJ}Fh59^UW^)k|AKm#MQi`rX~3tIfAeml?FHs#Y7M>pnQsh+jEg6}$+%@>?a*K=xTHD@laSnV__sr}E@{DnkZ z9vZjawfU6Zb0h$UO^~`s%ar)9VvV%dw5*eG`6Vm9#mIB+JhpUcX4twA;2Z?{DpNW? zluJQtHjuO(dMqYgH2RW}ZDqVbYNwKT`x=g?F}1Tu7H=^B=ldm!tV+N*@#^%faYbx} zHh#tC5{a0bgKt{+qZxDO=i^PM9rDVIBqUei;*|8J3new>9l0snoKIsThj z4%p2-(JFL^{I5A_9zI>g{I0#()Ly#DHSye!zh*tY(=j4Md){Wf?xZEoOX#dtGP@I~ zykgq_1-F@UXmR@d0o3M}+MGGuDnGB%X(BU*nMs&e|VWhf>(KgLyYXV!|hD)36s_c`=q@yrYrEW#3(@wmR~axlE) z(^@=}FCBI&k}$u+t-u2^Z+kWIagl|m86}bJ@Gz!#3q(+_R-QfR>)v9 zM?7}n$*Z)P^Fiu?i$ z2(0)2R8-s(7%!J2CXQWqu^-teQj`EMWf55hIbvNq^c~$ag5zs;RV=RI_QacQbU^|p zRz*-}@+DtW?XVWAZ+H2&*Bih)O4~f|VCSbEFf5I^Ka}J#%kA1q3PuAHdq<@)L{JA_ z)Y_*9FFA>|MxCr70(@21__ia_$CMwDoGJmh%Ee}cjfbr}jCy};D^!5k_2cv+d#qcJ zcM19(rHKsxAgmjLzjt!t0pb21zEModDqPd5XQsW}4Sh(eZ$hPG+;`7Z!^qN82VX1c z=9EU$5u3!eas2TV)*M8nWDg>?uV@*Z(Gh;Z+>oMRpo~DC?LleKy9m9{z%=<9^-Puy zY;9Xu3vJ21;GFxWKn|$1OK@vv&24LhM@A_SEsnuv4kgKG)(L}}G`m&$g>oQ-)UrcC zo$N7U?kP7x(`&$&#VBCTc*COI@-wJ&420;;s?(vRr@H3sC2;h3cr^I;pyY3Uo@OZ^aPrxjNcE{KVyKa>Q_NNIA08@JS^quM@xYdU zzIfZIs1laS!p|u0z|+H<6g6PuO$)+f2RYNay18zY_2dp3GgGs~`+-4c{|nZx8}9kS zIy&o{MtpXZUYyXqm&|OZ1VKl9$Bxu&UR%)AP%dCJ*FB%3Mx6V%4yDnl*dvMST2T~b z3GD_{1+l+o?9$ImyU)3VGBNaeoK{bg?b1mZT?G=J0rBP_>GZ*@e(__S?{ccL(_5mV zm9&R8c~B~rV&92)GOB-EwS~zhE5-t5a6HSh8g8_Po1a`6C*L#AoL#`D9ktgT>(_wE znpW5w*Ym`4EOmz77mdA{F0nWy z!0mTZXNBFmC4931EP|Dr3T1bb%Dvkoy31WY2`;HQ2{o~Pi<{EKVR4seDFj}Dva;3G zB~T|)HecN>uv;SB(-m#>p=vq!pjN7t<)Iei_?=rGV*wI7TKtzzz!$w>Z0}D6Z3Qv5 z8|JLp;=e6}keB*=L06<8DA{`MTY(fJR3I7DlfO1P0Ml%#zQ8oQD9bpu%IXJlQ?4qwDeL(f#zfj>Xk3I`7VP6aEd90Iloh1i2-@Aa*Y@jLRY3HV8 z+#-mo`zWg4F2L48<@af%FY15-aVUQ>|MGjKUroc1W*%tUx0LJ~yrQcAI%<@;`8#}x zcqr}XpBXW6`{ogKfr13v*EIsl!w;k!y;&eWCNE#tZ{Sh^^1^%ruh(5w!it{7LQQow zYbArDzGxGX1zq&yh(%YSjcXRbt>buH{U5+oQ0dgF054@sVWJ7a*8O^~o(L@2^Y?bt zLI6TJcIN3()WO&+h~!W?IelAO$(1MZN1;h~pUl7zxP9eo#Ff3EH^|W59{%?Xv%|aa z=G_+#D2nMD>*C6{LbRMDopnWMJpajkA zCC7E|p?LD37qFz_ZceWr5+2h|SoIz#`3|4m9u#GC4b0K3BV|+f_Hh~D*+6XSmF^D( zDYdqa;qAD)u#5jX+j64;{-p?iz@gp8wI3!m#AH1}flcq_@yj2N6^8c6Q}+cdN1c~7oUp@pk} zqFkP88u#@Wo^%ta>-gkhY;b-Q6vqhC4P#`R7+%yLCv9~-UU7FB6v$9v5%)SNcbp{D zfb4Jsa=1i-2!}`?MNfqll6GfAu3D3TMe>>}#MZ}2e;{Z-^Hx}t?3qJ>^99pOYC5x_ zYI=ppB8aQl(~_f{rXH`L>x0#JI@!mo!Fei*{UWL3nFhq?-M?$IG6Bsp<|`94>9{ns+=Q(zml0FMc)(s;!|r zZ(u`p)$5Adrw){JG|?kl%DApGhf;b5rd|SoyJM%Rf&dxvJB&v;!;O z-O_lEa|1v0G~stle^+?{Rc)RdKE~nImR;V31(e%i|ELFm<<>UD&>q^a5qlba9389I z(gQYQuFB4PW?xtQe7A6QmW&ME%fUl0UzTPI_IXj8YqWdQj#JzG&M~2Vlv9w1O#}om zJv9hgPYjBj6YnuWCxyrg950k#?V;7o!8YZYmqg|+!e}IHX^`^zv#Z1quy{-5OmPla zZa2w6eGmXRd(dEGWB!$$IS4C0I;c=@?U2ra?AIDPx{qCmUXeArIvLcQI@8?7M$b(1 zt5lUa1KsZ2RccTmqRkSZDQ#ua|gv;x5VpY)RsLWIJE>Rb^R9n{((|pv!@+ za&R^K_e2L6gVI8Y^81zR4>w^^E|na4mSaywt=4piH0*b@oZ`V>XS;Tt!T?AM+7OQt z4)5wT@RBg!g4`+x$j^id8J%C1Z*3N=*U0lR6sZJIUJyIml~(xp(p<1a%p0hshAZto zA_zdC0V+eSkl?4gdK~FHx{9cY*`(rTriz)EXD!6Om*LyhAdq1gLgJ)U zhzbCRn<%0B=6OCu7WP^>b?Bjj_(t6nL!A|O_#JKH7{&FyZBhN)G-;XtpsMMye`;kJ zxXc>l>nuON0R>7`Tr=5OtFbZAA^@A1M!K&n zju;zg0&bs%>8!e4b#4;YT*^@F+@|rEcTS(Z1}JrI+(Rq5L}9@9Jv&UA?{&{=5&eNm z3!-!|A1`DFql9Fv2R|x-i_1(5s=Kegb*(Tk6NHL9Gvk>GKSiz1x{ds6w3_fHKdiyM4lNsY8@~j+D@Q7G?mWl0`V}^$3j4m`_ zZBQDkqT(0amhQPG*h=oH*lVVJL9>RVX1kGp_P2-w_qcRMk~ic0d74gk+a>7V%sz52 zOOEwDs|Z}oZ$g96Q085b$MtPjeejn=KnA3zPIqMaeDNt*&bOfX574ZPbEyt5Z(Q8Q zglbr@dixFYFN%Nk>cyF*Q2m$pR=K~J-#;^f7xXFEY16|t?gk90w;UEkH!gG>G-vQ+ zCDvkvv(KRTi)KI||LBM$Kgd^tmeufl%AyLD$B?k)vfNdlr3OKHvbV3yYTZ2BID!ikA7-<;+}kD9!30wnI^U$M*OKu2`ibEdc2pp{}%#>;9^qh4K`! zcB_1i+)Z7DmI67x%IV)ro40+)6E=S^*IQlQt?!IR_Z zFW1n!xVnZ3)qGx%r?sv5UhO})j%Rng!8_sH>G3i+vIL+?*wp5+BePi~K_X()-{$a8 z39%$fPyld+@ik>9+(K#aVdx!%K2b#R*E7U+^~=P-Xj6y#_utOiG4t{RP}3^T$VYMi zJ^fa{F(rtN4s59V=VN$pRWOznq#u*5J-TBIOhGW<5<@(A^?Im0>&3~uZ8yLu803Oc zTehZv>#RS3fG?N*c5$7q01kSY<0in=+HH`nAF2li8@eG~$$?cUaNZjKvX?-geBSAP_8t&cO%K)R+h6_3M zpY7eWahXzN6{%5{cRJ5a^W$(MJI7{*4q3>@@TeN`$=Fryx?t^km0g|ZrahS|1?kzc zYpG~0_N33YN~(z9#*Fy>{}x%-s%X_( zpXqg%uh|z962q+(nfKNfXpl6g;-+BzWXWL6fu<89oipib^YNZEn5+#BG65?%{8dT*yNdk*J_deTzBlEVuGX#$Ta?%g z@RESVqp{`kImH^Dz;c?Fw4-ne*Fv33VIO`PS9%_p8R7!&2W36}!Bu2e-2;IG<^14> z@7GiU_zBlJbJJk*m)lAjU7d$A$4bL?{clmGCW)?ug}e^m{2VgRKc&Tx`iDmU3et{m7O3@*GaKSkrTY+lSyRilN6ml)dlT>b4HBRQZW0;b z)uLhjMELUuM$rgPVAjCp`C4#Pg6O{UQ9B_`VFZ4aBHhSGH(z8X$3KPJ$BRG)eTN*M zeMT?t@}|lJN5X{`3KZl+ zxO<+{wZ%dr8t1BqQm8k%vLW4*-DAeXV_eFA?-r<2g~f#$Q(7v?8OK6vSdFi%4u^(mr_{`wUrXbcRhO+Q%Z9pC)4$v;sGd0UXj?8B61R9S>D-Wis|&*0-3cg@T1mP|q2{r{4wp z2Z~vyYbA7#$0Hp`t+NGJzqItU92pt*G}iIySqGZGvcY+k2x!Fd=8L;WltJuAui5=QtMknO`xsd+a))qX6Cs$St)F{#- zDZWAPP2Ae@rgg$|tM89pMbm>q$O zKlG6FN?)h@qh~FS)R}k}B9=DlJ=hQDss;G;ee7j|1?@!vd0v%O+5JTsv2EwC$3Bkl za>6|9gGP~-S3ZjFGxIlW%iFJd9ZzGX$62~?_Loa0uG->gRernOc|d*wcoT&My-;N@ z4VEBK7kJwd->!X#Yo!Yj_igKc<)2in|6mP@bThl4#vfx@8y;X%nTfcJ+MPqC_dqkq zGgUF3hZT~4FI;yC%^fo^RS!oZ`!&B7Ij_l>L;1U7*N$^#?2;MVY@KL<4hX&V##eMz zovsvohdrSGXkb$pBvq5nN$ZWrn2Dh=OCChskT^_VV~&!&5K&`>#hd-rR9YMyS(il6 z=|a#|bqcISlvg}@E6Y6Ivku#LPmrux>i1V_vuEfm0mNt|5)-3C!#sCHTI+_*Q#?;1 zEhn@c!@2K)Jr5RqG%vdS;;WCf5`V$)RqLW73^$FOR~DtEgLx7KylMR>$IQ5O&Zfvj zG_b>8tL^T<-2wCO=P#xQztPQ%*7z<2i@u-EikmR=I<+HR-aEr6E`(jw^e36;Z?!;t zt37OcYROiXsd_3MRPL`3hkj;KO^!7Rj2dzeQREoQVY`0BmNmt;B>c7996-DXKOMJW zlu20HM+{zw4$~Otb$Vt#8(H7;cQR23B$UBw&J#P!`X)o}($?uQ^RO#s1z@5PXYGcv zT=px=Fszv$4A2&V;`v6YL-pPyB0)lDg&s@OAA)nmHXX=6R6QaHj1F2fg=%pEq4dmX zA}g%bnv!h}7f;$%J*^si?jNY>t>QA9 z`&bNQ+|h8+kqXlLHKgv!3Z1FrPoMUk#<78R=6_^*9|a&SJzifN`IVCy1S*VRkD|=lT9&Yiy$TEzc*x6UC9MY0orF=lXcLoF_edAm^85N`UtWTM(I3kr8KNJb z${AP0Y`k++Q&XGftDZKzH6LNp=XASxYsvIAC9}Pry3;QObOXF6dHpTd%HL)+hJmh- ziExt|EXpDhG=I@@8S-ugw+Tbr9$g5rk;ewqj}FFVZELA3J&{psZwiXzWaPz}w@%4e z)+s>CbpkTW&>^WgR39w#4hj2WzG2^^8<%tEP-AS)S4Uu=IvQs)M+e21P>}|&hK^ya z*AhikJ^ODnry}o)BLT`8b?&*NZ`th9pP1%fE#vGGbsU6OnTGgA^VSZY*4Yvfzsy}T zl*Q02Jsp^oxNC@?lGEC&7FNJxwfz)j@x7{{fCKN3&%Q|C-Z>%n%#t6DN0oHQ^)R9; z1OE6H$Qu9Twqf+2Nps@f=0?j%%sEQaq{bM;rgp_|tv0N!wG@W(5S5l`=Z08YNAR-> zrlIBVJY`EkR%=^6k6IIm)Oc{IxOcNMlx4+{17bJPEh4|n2G){VK4 zz8*z^gkq0x4b8a3wqN!OU1Db? zVIjFa&!GGb;}d|cGhpVZzv}j{0zP|yXKiR+*GamjdrmEs`t;}SVi;;o+E}ZF5eny+ z%cy-79>YJ3JS5y8m&)LzUEC}sozA1oPUn70^S@uh9OD)e!Inl~Td8aJ%b0!X=b3?S z$_7;>6RY`M`3Yl7o?C0S0+8uO0fKDQ;ZTYj1sT8P7-df4&natQYb9*V7CxKnqY8Jp zaAmZ;q8&8ft#xA?gk}^2vEpLTe_oX}rFC~Q6H*x11~AKQi!=1epJ6tqQo#hr_ZKy} zFJt$)?LL2l)y%b&p^}!ZV~l%oID0W+y{;c%jfaBL`ol+f=*G~c&XIfSfKmF_88rjh z;^qyq|7eVHoYl#^%PfV*p8x@5z0=KyMQyv;7Qo*yaop+gcSbZnl=kj)oR7NI(xUz3 zCd^F02sja8KCvjv&ASL`?+b#}MLNTL&!}CKakr4vEmS|h@byGdlt2Y4ldtolz&Glr za?lL7i7yhi2aS1d(dU_2S51FSaVL4l8!cTDIKk6p0T*`26-v#Sw0Rz@xh~yiCNwyd z^bTrTt+98ej^LY=f;aqMe-pBwp42apTZ%xoR*NA1xqdR1Pd!ew4B1;alGW>!@mzU` ze=pfyasl9H`BuUG)vUdiDx=y%$)hQpvXaFz@z9m zWN7`ygLG3|ou>a-eUr)nzb++g!@lX|E);N+ z+nCYOt#iJ3o;G(m#m1*8q;y@U?D&+r$i24WeP6$t^K$UQ6D=}OIbL^r=l3$|l)NZ2 zoBz$+$<#cFtMUT@EzCn$Lntt%7o+iG?jWR{wDU~aMR`!^(dVJ0Q5-`?7FV4A1QGvQ zk|s0O==^I0r7-{Y=8qlkD0Ggo%?G5HmNE$wGZz!LUL{lmLo!gzI4!iux^>dgRG>ZBry zuf13kRTh|0n+58JSnH3Ggo`9^<@A%lB^Oi;)7VEDfv*+U2frweIzp}ZB=hUexsj<% z00c0fJorv9UJ-O+Qx1qy`VEFGN4p*6O7^kU01RYfAJ_&5Z-4LNk=;KfY6DqSq>;oSM$*%o&;2`umP&xP{;%7!RK>UyW&XOOK*?+hwOAxoHo+ zL;j`9nRnF1w56S$#3Tif@je^be8!!_#893_{(3|C*D+E-w%Y3^YkU8YOw*6XxLndm zd1PfM;To+3%{uazeR)p!A_z#?6?kMEpfBHq1j=rj!R@BES!CdcD{7)ghk-L_a5zoi z?KbbkJHu#Tr)!IDSt|=o8OJp~(Ft|FUp{f^Z6f`*hmJ*75+i%`_x*8@ybbU1Eh!=e zcVcaGWE~7CtXgrVU5i}5ul-hp;)jQf_ScN^+-GF3nCnUqvIa$oyr1Qie}pFj^%h9~ z5(btQ0)-x?d~kBr`H&o9BCPRje1bs&fD4q-!;E=`ZyIz(&!03CjC_r!dd27hG86x! zK(os!5nmPvdG=RY)RgE2z0dj&e`#fPzfX*R(N}Y=n}GapI9K`cM=-jdh6w)pMs*{B zg443*M`v3xn;Jg;xH^AI_$-A2f^}o5Yw@FcAVj*4+2P~0Lw3MvKe^URHYuz*w82!| z;?5Kj8SmkX|llxqA&t5*Zlteo@25Z<>x!d5Oxs(7+jtErT5$U_oyebd}4?u(X2z;Q&)c+^Joh~g1Ha0 zmyM0hzc2@J0(e5GVcnXN7r>9(bOB@Bcg zld7Cj?xuZTOAslCMjv>scZu+e2vNtCBzWi`4SGwBCqb%CSe`xd-m2!h;bS=4tEEqM zm9&cZZ7m-ZdBuQA6N&hkzw>t*(cz+55;+&Ql9IwcH_=|-t@Vzrkw}|qKJPZ|Eburn zGsNFAUV5RABCA7{p`uQ`Ae|o+^FBZFsE`95Mx|RY=8Ms_Q*DuO1ZSx7Y@G9IC7X~S zR@8+2qB04Fy6IfBoPa|3n(qE;`{{GGzHNVNhMEnJ3`!}wiDw$VW@ybp`WZ2|-P7Ej zWUV{$$J0knEjth2|CY`dG(q9OF=!$GK>3$Y< zGyAb#42*i(d{WsxD-9KximRBlo^ZR-=Ml%U&1;l>0!%SF)#6c`fA@?a8KB@!rp*>y zPZ97qLrQqYP)#FUaG@VKu!pVxAyiw87H_vI5h@CT(W;eCXmqb5iRmXsp*S4XQ@`NS zccJPYnM+7?9Ns@S)wTVX3unM|sEe0=YOH!5XXLpUM??+7D>F$Q43cM7uRzux7hmo0 zZPQr;0As+df_qvOHXn!>qs*m%QSQN@qfOT7yIQ!u*O?%`9mx*j-5zUnN|vUwD-6R8 zqgjckH2sia*V~wT-3(8Zg5v(S``P!>Zcd*vP5NU<-ytCyr&?C5?6@7Dbx%@B)#usy zL|L1RDVQznL+){#@-X^lmeQiCy0yCwaW}vY>Oc!WMNa`dir~l(K~lKHa(Ilrp5NY% zclqCcuLRG_FdZc%iZXrIQnSwawLF%NY+CMbQYkzm3JiSRd~&*HB4;6 zpm_4~jP7JQAx+F^0G$=c!L@Br@P0+qkz$!=-JV-)kRSkaYmdvVmVs1a)KCFe zP3G0L?0vhmb?ofCWK=fOk)TtDx^aeOpF;jf=T!~D>F&1u>-Qy8)ba{P2~ryyxNp$k zC(g~Wf_u(oFAMFbD@R|XWUk-oHBFVn$SqL)S?l6Al29&;3{z&+O##g}SWc#1-FaVK zbNru=XTf+A7X0mAvO`N7&I80|B^f*p6$;Zg)16q&wN|Cxy#2Wt=#OyGvz^BOX=|-Y zN^eR7{lAvuh)-f+3Ta*f4j94oi8m1t!Fbe09xVJzwJdpgL$_?*`B*+MgqXjO$^133}tm<0y~XYS4iOW zpI4R`GG<2(emEi#M}XzeOC;9(T>`0hh9V70zG+?mNUTWvp7Mqyur{wWG>k9vq zTxNC_(i)Qe1=F*n`T@n$G0 zdw&egUqm{8N|XPnWtTPoTenU|wiFbk1r3(W+&Oa42MyNfyF(dq7F9-V+5dEp384Lq zg}4*H58E+%h0vRTw+lu`^}$ZYuP5yzFp4%5yArebyLIp<2t>kRS}9>T&t}=otbQ+u z1+SgF?c)5mrIEP4B6#SfP?+XdlXUOti zQ3h#O?M%OHn7+i{`QWqxD{tRm;h#(Bvbt4>f)~5HaL!q4E9yrxtzr zpK9CLDC&;`&@80GY*t@2faVvm?f${+h-_4{G`uL+OS5lf zI-Fq97@LZYLYq5u^I8_<5Vq9!N9If+|2Wa%j(X56b%Z=qz1nSUFT2Sow?C>Up3tc5 z7IXyGxuiVEw||gA4Z66pqu=p!m-P$&YOstS;Ak`1w{hx~HPnEvghnMd4rK>D`MHF+ z5cIIrqt>PR&Wc_jKa&jkx`ewpr3Q}(T8`}HI9#r`PSX|8M@UeS>Hv$aBu5q-h zA6#-nMiZ%Z1LqfibZf5?LaBbQhr9A(?p}_v{#cjd5)H7>L#*4J2>15bQzeMf}+iv*3k$Oa9Y%l zOVf@K5=bB?ZA<)uSM``kT0j5k-Ho`M@ygELPVQS22x#xeVuv9z583M)ebg_W3Ma*3 znz)p0y`sbPK0O$r6}fqCbK|FOW%x`81~ELC7^Q#|Xud#|b~jS>xZ)hCg=e%0{##JC z3F+JK<3$CJ)^nF7ooWz+EeauV^(?O*6{x|$c@5+kNAo;3e9wsmDERS%gF2g{chM#T z_(Jy6C}f{57FZ6#9(+CCOB5dWxb=~liP;<%<~`K%9cP)e#cf{9>2G54$+%Gs=GM~D zP3Y$TErRw3zU-!w6cM#8IE?prBsJV1qA3eQJTJaE2C%4Qlef=aC;DTA&pa!}3;9QB zH*i=XX|g%nEdd-VE}kaOPTtU!s3yd3Y#3-3Bfo2YC3oFOJLo+B_l=YJk*^9RP$aSp zQ-=iIK4l6XQOJ#&1lo%@FgU91+1j$b#A1g?_(|#eHqG(lFN-jEvE`d)PEfA^TwC-M z0aVEzwV3dt-LI@@DgbV#xX)QmryFZLC*9Zn_Ao!rC1wGd^lz=?sW&BAoJ;>j7UN&m z(#Bg0_`+ZW*_s0G(pUh{OL%U`tJ-V?_Ew-5#QMVSv0maQ82wJKo41#R$C>L^Ul@tE zeJPF{^B012+4aMg72}tGGD-}_r(meOXJ)7{c`QD`>rV#d9soeA1Q?YmH`ePhMw>Wx znv;5~$l5gtGOzj7#mi{gTm=MiXh{G|AvBvG?vpoVSfXV>D> zTg?!Ljc;6xIFQq~Z=mYih1RYjSAG}~HC>IUHvSf!kVgUj;666ayQQwC&?wLtt1${? zgsF=T9GRpPIIufpl7?p{;6ak6(4MMuwpW~|L*9lvsp=4&&2^1+`*T{d|?Rf!=a*+Z5_W;(rc8cPERJIy-Me&bvt{n%==G9sb@n-})C=9vWXnHF*B7 zqpvC$Q8iG%_~WN({EymQ9l*HL-OHw?#z)4l{41xvnk7?nCgA64UMko*vu3AO^H0dq zl&QlNOQNRVpNJA+Lo-!oer>FXvK$W7L>??eRB>*C0_7E0CDF@V=QoS8Ht)c&kUTo| zwSWp zl_Y-=SPdxIJ1%lMTE%VSQ*X_KLA=Es&C(G0!zjYv08vT~?%5SUS11Q1;wZ(fXp0d7 zC_n4yNW>B;A=~knA6yoe76`;EVJ-FC^n3Zy_RjwuXlVy#Dk$sFy8a5!B-4YP+#EBJ zq782Qy^~(Vdu0ELOE|xpX$9Ckg&DWIc!=y+#|S|QNc~GJITgHjcS_FS zSDbd1hKTxu^1G}yZD7kuM!{j0IFKq z6ri#h?{_%1eFb_mz{P>@5$t&mj${DA>H335R&~Z`W30h8UGv@ae~V^eNBw?KOJhbZ zcu-Km7n782t~`d+-?Q>E#qCFSM)e}(u22mO*%of4VVzz&YxCv7@1HfUNKDV!c{Uw@ z`IQtfiIy{^MgKg=Y%^ZCRrd8<{04@K+Uf%jvrCinG}_?vT=s64W~>j1J3udPXl?7r zHi`ViAPWB^vlcB>OzbAW0xGkGdt0m<#C_aQ0{E!a2jbGB3O$R(baem8ZQF>JgvQh$$= zo#mNr25R~8h1j#mu_dw@9?<8W_>gX~O)de;nVBJYys9#F{X>*BMDYPv2Qqi6_o717 z!-(fwlS9Ky&~h^TWOW{hT=L0v$$3PCr1F?p^>p~@rFY7wU#!kC+_wa)v?bDm9RJ}p zmp%?p;LqxMUpl7)M*_}fqq)B&ZlS1Z0ExT`xX7A=$1b1Ac9cw4-#pNiIbUag?3xi+ zZbGJaw*7C>aX4}66Pba9*<)6LVc#ucUja+SAP6hgoRgH1lJZK=0I{B*N|cxQH?Fy! zm}#xgU?4pW|KY9CxvGnm{HssUE5O1?sL~v@-)&>=Ev{@hr7wl{50In0^}cmOXHh}L zdcvOgi#x+?Fd!}&ryUU3#;SGGg!TiFW7erLNcBO-UnZP}w>?f~r`9Vne~T(CpJE2w zE^smAYF5V6#`8!8Fa=s18cgYRH-8}{Rc(5i^bc^zN4_{4_VBTrtCs30*y_K4IQq&1 z0niUkG?Jk4M57y5u4A>Bb~`tyN1($hMVOfrR!uf~sD80Th#cB@ zu-uEgLHVG2(tSg&Ou{|YS?-B{r2tx~`HKD($h(eV8q@3UUv9c&sXT%gD*EgCUTef! z20+g;JDuUajHiCjI_Y#1eumt>+6KxxmZvqQW-DT|b|P!kLT_T6-|DuAN}GXec~wz4 z2awFS4TYkV0oM{D(sB53>s9@kq2S{e?bQN_s(!IKZueO{hwA>O94gW1!d--H%qoSyE zjvh=x7e21^SMI1y%Ksu9hd=%x;dTK>8u_1uL8v|uqtS$7mrfy!v?-UAZM+{@{yb`K z+w*%30_uP6xxV^9&e~!jPuI7xSOnR0+8OU40h7e!yX|`|m;VrxD*w0W@<48hyn=o& z;?oKRG-W7J_b_Gq3iu5(K=afPgg z3q#d%FJL5S2Amq;s^iW2)7<$V375Lj^pemYs+@#nhYgCSFV1NJPUc8S0@TUEqW$j6 z7hVE>#qNmz+cMwG+U)+l`~BNLJ@Ed#57+Cuo>%e&vtJ6=f2C}EN8KmV z{gZm$BM{I^%!C4=p9FT{+&0JVEA+N~XJuobZ^}l0p=kytLsnxmBNmu#o3hMiYx>{-%e~&iP)iydua1E~@T8pP_T`q8 zfrL`{R7UfcO)QX(Uq*SOwiR5>@ofSoSFCcx;jNF8lB;(l*Kx+8Sd3Mk$UEzuwH|qT z81V7Agu%nh*&k0#v_^=X&bR+bC*jT72MqVE;caBB zxlz0fUR2(lFpg7ghaU=iFW;sJ>efLb|F?$fws8OO`0~TS6sBxUFa21WIiQ{=iiBf% z4c%aZVoHuqQ=n2l2Ti|Rd$8*2@E=;(1l+6X!g8`kUM>e8Ga+Yao}T3OK#<2y52dYq z1>*AFK^H3ANWCVnGh9nE)&0ZCVO|-+Rx3*H{*GLDau~!4h+9=5B~FQcAocJ+&d2jN3LzYElaFJ_OX>Yho|q!yRKFjcG3Ke6zU4bar)=Wp1c-K z$(S)T&rns=rm%R|`Ai9vydao`nXfS%ofHyULUMTV$-Og@Qj)yjNa4Ok)%YYb0-_N3 zc_^jVEeM`EWDvkJ&CfXUQ|wMn^wFScWNDl0<(ulkwxmRXv`hrOKx~h7=;5QJWC0}b zb!%Pa&vmP1O0e4xyKl2;>6m3!#*(M2by(5Sh4RkuFdLEgGX7NZrekapS?E7JcC4k7 z>bv1ow%p2Epd&I)PjK~TyEmqH4%J%8ao<4v)wih`uV!QOqiLHO+zKT4P5`N+fNd)2kpMtZU9S7RVh48aKT5Wz&%> zZ;H|PB`PvfLHee_+9i`ia2_YmzxjVF(>`C}CLk3mEx{LN-;zOtGeXmS0QeV5Y5rLl zp5A}WhabrNyV&rRU3bf0#P92OV@rSoyQq>xQO3?X9QHy1zC6(lXPO;z;+bbgkPyrk zkS>&&AtPX-M$ng_?Ogr<@=1X!NmWw(aBG6JIF=MnB$O6X+cc%M5*o{&*BMHAc07HZ zNu6KFb&@jSL_@1hn=7oM*KLpP_&XuB0gDtF? z#EUgjxi9)qt)$?jZHB7Mv~EYb#Or z9nJu?8xVY1%TrrS%WgqkPNbiqd1zZ*PeM>fTcfb~zcuGxm9Mw^fK|e(m zd}qf|$R>NFgQ$d<>P@5i}=h3naMKEw|gt##c7Y1p!AF z8m|4Y;Rt_nkN`kDGBfA83V~h_yse%~bP8|DXPlonCN7_VBnnt;XoI%ue8TlJ39{*zX&r(zvD%mKpO|9wRHmC7rDeq;*iAm-T}#c2L*BFC!=R5AlBJ#p-D{2JEc(Ey&8O zA`N*4I^Fk~!5WDdc=w3TCabT|t>(D;Uo`*ctyzKV*J}X^GF$*3KDzo|99#-T6(eOz zlG5h(e%0|4+NcBwhl1kNMNR+mt1k#P?^29h8Ev4uoRjW$qtD&pK(yB%bR9h_mKcge zQMD|K2=6NJN<<~TZbs4oF3yJPdVA(64jBe!y||+;$SstF?ySa&vN_Q;wjy6VTd5+& z5lpU7^xN@>Kq3h~_wktfgG6lRN{v3p;M)&j#H|f?kcA=e7b$ZF;}R@&$w+2KJ@h!G zJeAP^Ui9E3mv3q!xp*ww7l$++23neoRBn`pC^6Uyi};FCmIwK#ni)rQhX2!SJr|DO za|h<*Rsx0|3g+I+)3XpRLOUr4MJ@zu1&KGNU1 zBI7rPFLMQkcEnZ;L{jq?=KU-z=Q2@M?AIv->*gw~>v*ZlDz8{L7IeGFD(rD(y^J&8 zKI%A|l$PHFo%YTF!JGeGBW(SK{=c1lzd$>VIdhIZ9xbHM<~A`0*e zOuP1!Pc@O#8eJ?3l6YZiP`3EvR7;t_;K33Qv5NTwp2@Ip?o)gNnTYV4L@f2QgjAnM zG#=!yYoGD^ZW`6^QGYFdi>NSWDw&%kNv+P02q}ZjjR8)d44yK*WT5%`VARN&D;vWU z1|&k_(fpA!)T)YBapTyhY_YtAl`ZjEDXPxl>L-6K#()_dm9l~xWgN;Qe2Iz=caXx9 zI;Q^||I%nz4=|!e42X}bL;Ev7jk#?@g&QoCXXytw27+s%K6Yi!1o^Kr2d>dnn$0;+d5FgNC!L`fx-e6n< zbZS4SRdRdpe`|mSpvuB-IV36a*9B)0r$+pe3$S6MqS65h44ZMFO%RgM{1q#KmX# ze`^j{M^d;!)33W`--O1slI5T~_>|E4z2NcC3mVmP0Iq&F58a~>FIP_MGq&dmG``z# zWn+wn$rHzxDT`5{LvU$>RS32`B74h{@p?S~^mTzcv6KEnKFFnl&sD`poW2B znb&sk8R2Hx&3BX^;7-YZd;*aJTPcUYw`r(vVuh+xuqt+gV#5%FR`t1T+@{afTQFWr z`UrfUVi5yIg-Mv@+lL%XHC;as&ON1lPqZq$3DO-F1%|%Xz10DCN@CX|fR2fNf2>&P z>y{rvf_0E_-9VJ}z@hqGD1}%)$h;KFzyG-YHw!IMy*l?k5d7GljJ>CY&5IUKuU}}u zHuGYe>WFBP-!2iDFZV^hDn$%_D6i=Q>{)li3UU7$F0JQqq^j26q{maavQtb=p0n=c z@14BCtmUt1GcZJc4T?C{2z=mgEMDi)X86B2XcOWFB$+!`p!dp=eA3*Yl#)TMQ+9Gzo zSu$w<eZ`2O=ra+p56=}KH4&t{g2mq4=|J6 zi+G(Nq2l5hNQM}c)k>6a8FQr- zXSd{8Lv_#g;AGcp7aTY+q>vX^E#K6jU3zxT{ji_gqE8X}+~Sx2*8F8FK=sX9qV49d!oB52d> zqk%2g0{@PJI!GfFam`Mtf&XSo{4j!}W~LL{*^TDRT+6dQNBn++j}2La*;P3@MYzBJ(~3 zvq`Gd^!x=a#AX+n+kI zp5C4iiBkU9|3M!{o4oy-K-UpqHx%;yx}e7Y)jMP7gKZk^#Oon5MqA1+xH8|M9;_6v z_V1wE@AH~M2Th7~j z`GC7h+5bmRxcWojFqfGCwB=69V)GUTUFA(;370Dj7mI(GMUr5{i3T_Ef__UE@mO4%X85PfyLF8I4` zu1kXKkf*8Rs#i0f1Y4~akFBM=Vt>9Z`>Wx+m^RqZywD0v)c?<0jz`ohANl9HOExPj zQ&ywNZpJQ}@m-UwD^d)4INW9X@VgRFAtYM#IhO=5UGctzD%q{lp^r!@mJ=jT{L?VG zt`+B&RMmw_FkE>NRA`X`-u4stUb*w)A0{pv3(4PKh>^%bFYr4J!!ywKiy^+94>w5a zRoZJBl49gEy-%epnZ3MQbH@>ki-#X&x8KC-Ja9`Kh|jY$7g@kpMZ!-H=8x#Lwv8%! z<}52Yq+TYnIL?r#&?DY$>iIaId1{^OGGHBmf$tnApcrK%aK98B@v_aBelk2!O2H=2 z)f8`c&sv?20$;PBxnB`fUqM5xNXPRbD;hskp674Os+(LZ z9upi4a~c*j%hHDQ#XDD&^@j2h+EHMGS4!W(sa_$E4c6er?t|KyxrJqOwed2nWtd|E z#0E&>n<#mC4kKVNRvs_A?SU%B7SFL+^#kFdg;z8ReU@s9de{tV< z9);Ba|HE-Ep7^@IK0PFi4OA-?$emvAkU53GqoQPAg~{2iONgon=vP@`{?KO)kYpWDLZ`gA$RgPknK#&UK?I*K4^D~!)!5ba(Vgl!|23{$e|>%l zASk#(mo#nzBWLARDS(_bJ61He%5bV6oRqe}wlNotR#Ae=9RP?%*9UfCHVSOTndL;q z;Mj&g?GJ14J;-GigEg4&N(ZUmKVVnv@i5tFk3W`^{pUL#x7zkV4kwqfBxfGVQa!&d z#Qd}S&JOaQN=mZ+67XX+=iwap7hMDW7j_M8bzNdI%fXZImrz<`+F<1@{-1`ipoW%t zAj+Y2_Sm6TO+&HBV|*i8QOtuUp7`KX(n0tf|p z<};QA)%8;Uva{ow@62C~YbDSpp*|<~p5)~&Q@n{s^AZo!xW56Mfz(`%*MDnXxZ_(b zzRt19Pd8*8L<&bu)3?lSLIOg3W=vLXpA0nqu?~mm6zefAZqJ{I4b29AQ?bN#w}ufX z{57#+@a(f)9;%@R%jV7 z6L+^+{07Lqo;-QGuuE`*XZ+Dn+eUAv$g}aO;v(?l1FtJzO4)x3%$psxR3>*NAUm$L zgruc`zhOxPeJgap;Nrr$GWwa_Vj&zcnttroMFN}raW;!Ei1BwjZLwKMVK_Hd?Pgbr zz1IRR#=SRz^|?=(=8tQlFy6J$;M$61OnB|7^Y2Da|1qA!pf^U{oxXmLXb}xTd?Bm;alFLyo64a#LDONc z(V1Yfc(|tXy>_-6QMr5t49=4};g5AvU5C3gM9E(MGpMoxU>sLKxo$(CmBhTq)~-97 z2P}<{)hX$YJEvUd(4Vb3;qU=IL(KOqOVBboJv@$_dIMA>u&!ye8KS+W*4c?nIH!xaaEZoe3B5K@*ba0_9t+5Lh68O{o}j(6$CM`c55@W~8wU>-Nl1-|6iq$|s( z62Vp9Br2>n96{4f1na}@4&?Ju`#|R9UkGr|W_T?+1#N|EOzBugNpWrUzk;7v+aB-l zM$C{H{C z?~C{tjlZEb(;*U^JY#f!s>Cl1~*wk$q= zUOpCZN~asy@V72VQ@Ch{g-opS0h(J?oK!Y_p%YR)Y0m6g{XsKZ8@z=*WcL{qDc$py zY}29!=TcLA0O%w#x5GatyZx-PzQ0o;xP>r9*Q;0==FYwISGLD4|2svDtpmA|9*DL_)A{-jCXfNBBy#_ z!f@-;KB8*fsN^=Qr1H?um%)=1S(Deutkz_bC|uEln1?MC;?Q&CCLcLo_!|%3ekw z*f?lOqR8&^cexeb^H;C^e`}m}L_JR)_v`3Jj@B4=H95JFuCF^R+5_0$toGsWU?- zXeLoUZ12)}W!qJMV@<<3Hn(olzvG?70BJWEE|oT-i%F0r5MGx+TX{f+;`58c*j?P>iM|RjcY8MF;jlp5C1c62r1y;PRNTlwO#BYim*dB>^ z(z31jXO51&E_PZ9psl1UE_WyP6-zN=Et z6#26ZWdO(g48Mi}*R)!O8l@%PxO}Q}nO`esjMgnR!G&QQXWrD>Pubd^7L#&Yv5yd! zOq?i&l_|je1lIlgW-s^^b3>-$#Jtjop;dZlG~u^Z`reb^TiTcI{sT!$4Cheepog=p z>i4gZNs(NqXK<$-3x>R9_(Q_Ta(bY3;BTD28FNo|OXyXw8DNvJX&*&ZGJOK=J7N$K z2Ij!`@LkcqN#WXI8cFPqfOaY2hvxSAiX^H>aK>&*F$JB>MsmZ6PE6f5NgJ~F8VvzS zWPGu4@OfYB2W$obqi}-kUVnViks7%zeeGq{ByzR9ks~34bV$PX*rf22Y9I!MclVp< zZMs7@9BHTZ{I#{$fD>B z9FYwd5X!A5T_X-{U9u=!vH(^F|Mrhzl=ik9rF>0?&(;XK`zHSeUuJI-f(T)8o$GZn z)=|qlpSr9Z6Xo_a7-MbI;37xn&jbD24vkXQee9OCb#M%#4Sf42=S}XANS!u^kz<8r7faI^B%}Pcl)1VEFgl zT>mw;U`sw3%5oDcHWi%&WG3BA?F!hg1%aa z)VxWvm)7I0>NH00*bGo>;O|K#J8au#X~+SG6d}FH$Qq;OgXD1R>@}6t3=dAdcc#us zLm-nR>xy_Nf5yg8R1B|URrwYc^Ri(ol2hz9 zEyW1-XUylIEC0o||J-Nn)VJ200-V*E{CqplO%v+`;KBRFtoh=L;D4?hJ!X?$wt{zH zhWG?nkKY287C&?2sMgTFVV^np$A*X6El6Yg^antpyZWc@PpVGsv*-tdz+j2_8H@60 zW_8V?9{>YYvCMYZt?8@8UV;pofu}~Eoh@8;s?Y>7=|}#djKNogHoWdCh^hS!OcZ?+ z5=XZS0w;dYPANW4ZQEe$2J!kXa{?I;#m5P>X)V!8WDbb4Na647*adNwn;<74$g)+X zyEg`?d|)i4+&Xx5akI6TiWKOK_|2Xq{kVi9-Pkfd1B z6u&wsaLbH$j6A3i(%@k_yn9)*o(peT*wmSuU^z5Zpuaj^8`_f4dL7p#9LJPtE!;B9 z`aQ#FhKGYH_lo-{E6GfCSo*;!dLe?= z<70ptNNjo|RUy|is0oIidDZBFsC}Y9nYBp1sglyNeLsdrRV>d})r5x+ft~_A>iwxaPH=6I2utp?Wp# z=Hp)fbDI@|%vZN+l29iC&@Vc{{|_-V7%BbuyDHe)1*`MLiai%p5*d{CwDd>w{`{BM z{WS}v#V9U3{6*EI@9W7X2R4i!1j^QNWCE%d#15sA*DoXqOMT~1dC$C+w6MyqgXicq zBiOc8l@5K{1P4({c3_*iwi5}~?J9d)-(j>Tq|79|VSm9+HB86+$RPnPU? zm!{)70Y-rhM4>Wa@RB~jAanh+TF8z@q(AHB+g=oCtH1QQv8~PG$5_L=EKZ<>1qWm) zmqmZ@u~bhs$C-4=br94AZGLANzKbH-@e_;)jh%WSdv{VI^(_`X2a@K@(H(S<7YfmH zYDXaD2@lr+pU5Fi1kh17)fA_+x5%hvDA`y8L-(g+eB$qsl;xeFmbfOctF6wzIi44q zcR(mjl+!&}jVAFa03?H`A z)L8EP=?ir(xyA?3_SN}%?Fg+94S`qs2D)i7Hal@_@O9)x~PvCi~NM^4e7qfo)R63Jf`veen>X2+-5VZmDqqoqoP~K-=1D+r*fu^kyi^s$fNj4Kf?Z zV`oPc4`B97YXsIvohM*`78nWNq;8OFEyv08!F#f(<<-#1eE7#8HBHaH6?o^a*7scB z)tpd=gwO;|tAC~V6T^2*b+W9}|Ap>LaU2cRkB1rv|N3<1#sZ7#qgW3a?l(FWp{?{? zt`9n~hGge6`0BrPC+PCr&BvIaHU^aK=B$NmZ&7^riZ#^HPu+gLSDCuvhY_+~k8TW$ zwE#8^;_Zd*IMch~4uNbe3+Ka1qBtaKP&rG_dvx89FAW&wm2+h`fKm`~wl*g1z%?uHxl$?^QPv%1rRB+_} zOjyBI_cP*>B4VnoMI}cOz}E?o7U9LG4^(WA(vV%b`$MqXmBFtQP1k$Ltho++{~ii# zr}Ag)izFo^1(@?gu`Bx*p$YYAuS(JEi&S+!1R72lwA!*X$t=v};=U=uy7k1p!69-h z+;<0`yo=kz60Yw}x!^r>mVLG0-s)Re9HKVFhx6c~5+zz8P@^fjuNI2)=5=)e4n;FVu~bJ1 ze$z~VOXi~-9(F(itQSn}jgbP4tEu0@i?|v#D~ULvflpPc@C)I_D}u6wCo(36Tz5Q7 zC~1A{7LSRCO2O^7nb|tUYjOjpEZv<}J~+wX(ib3BCRY6Hu7r>!9#_x@ZhBhY{(+!^^INF$~7 zz=NoT{UR+i758?@ZI|zN%d5odv@iJvv^H^BEDrd`a)Pga3j|H0X?}S3JCQzL!Bu z(;|&pe~7ueIF(3=NlVU!^5BoBd`chvnQ{cYhI0lNc}L7mnHekukmSO zMw<_YCL}r@&(v}MkQoLED#XCoop?2^Z}WzoQVDCR2p@A|b}pHuu*A8l@OAS7yIXv3 z#li3A!|+xxyIqJPM=o)dLk!Rn_lZ0G%FE`S+v`4-`Z3IInjiq*gn8avWJ=wIn5IZlD`fFRWE*oD}8ASsDad{3SPX+ zcHNTv2kmGF&hT%$+v-7HtRqRO_xtU|%5EG{T+dJd9(_~D z@{=U<%1$QKKi#RO`$5+|H<60UgaIZD5-I~~#5!E*$4d#z{nHc#SwKM*E@^^)?8CtS zMTjaXqr|V5`)k;NC7qHVpUSXs?b6QLV<~wIS~$yj!%J8TPq!kn3Eqe%ia%K-DfL;q z-Q!YH9nw2f`V)n~&*uKgdbqAq6NTL~AUBKAk$pJ9noL5fSy3P*B}PWxU*RP8RGa_h zo&tB($e5d?k9K>`f`V=VGuAl0z@ku{@c{cOJJe~D2virst2bu{Q z_{0RheTcMz@a3Q~R8Uc|h2ECFr(ZkiF}Wsmy&7Ipt-`P6S$x)E;*!Cg$l^_tNoy4j z5Gl69_kDlJEO}Cnzl`oN+uiU^thFW^ykBnTb7mZMU~yo@MbsB840`lVNeX>lK_aWP z_zH04gg2W=92`cpBQ$=fRu6T;-e^SuI{m<`MWNoBOiCgXC)smhrkSQWBl6zH{pNSm z+V*f+WAnf4m|$CkgNzwgV!ps5ZRR3{V~H)|imYnz#cuFC(YJXnvG$nf@I)@Z=Jn&= z`7Kfknq-s+NR)XhVH z^wEj&4(f2$l$KRc-8WD%J~sL{fmJ){B>%?Fr*h_={(V-jc~lS;1E<-2cMp>@w*Y0* ztqfr|Wc)}J_1e+=+kq6(cMsdGc^>^z5AyrfXg$u z){y4mWmU7bGoYm3l@8*m=TYnDSPv3;9p7B@+NmjDe#droA$@~YvX1#Rg)cGH!U9RH z;ghS<<9rzvzEwM-_`Vz#L9?mo2e+-}wOWqaqX36o0Yse~2W&+-PvA~$rA@HC>LG*R z?X<=x=f>zieXhV{1r4&~yGgL^OucvhQ)|={N1Y#r$B8KnNm1q>jSi}JZg$?ZMSs!* zp6i7V$n;I(m2VpGAAXIHMij9v7!DT*9w!{v}4@;V$6@rGd1l59TqR-b}WSUGYj-&<`{ zSm{rbtPVuo`kf-bmJ6@54p-lH>npnz1qpcZrmJn@qC#Wp=ganj_&XIzk3e#enmT@_V!B3XpzwM8jK-;5J8ok@ zK7@b^2EhSYFUEiyqnJQ4Lz)~`_84@Cw~;yqPA9{_4#rGTzC zTW=%qcG7eVrs)-@v~oNg;raW+!ANi{JEkjphzaLj{BY(ticWs2LQXAK;}o*(zy5kC z{WJ^uzWnRwtemB3EftI zLTB>KPygw92#G7Fh}kD^xG(qjfJ$eBozMPO0(crP4E1xsb#86 z{pspFaVNu40|1zzH%Xj5n{B$5^daG%6o#5IWS3!pBY9$WCRUDXhAG6V*fw@VzSDPj z|Bi)^cND(+btq;|JM(#xWU&QE3Ke@IAht_rriB&L1eB=W^R~$3SM9=tD)iQ*M``Cf z{gqA)7C>v6c4dFdY275KDyMZxZetMGG?Hhyd5Fga-f@GUIwF=;2pzSS^`- z=?}le)p2lzE~iTL*kCY}JcnO$sJKPy|8GqZ3=lf;`VTX9y%S$%2cj&v{&?ly3BSW+ zz=ROak3sbOO<4dy|M}(3zY$#EWxMFhU;b~+YkSKz1ocFwf6=^jZr0ku%>FQeZW)mD zFP*~o*Uoa@1ic`l3G3lsXl;3yR%@VNLt}u^0u>oWWZw<*Z65$K&X+_^0FGf;c6a*p zfE)%BA&4ze>oxm5Cfrt+{8#f}T%EQFN@(JI3$hKoi(~h{@280OikBpj^^pUpFP*ar z9Z-}3|FnA`w%-Rumvq3735Q}0ZC}$9g8O^DKX*pWfxU4BmtuP`=yRo5-gmc<`THt6 zb{Aund!c(zn~5FU2TPa0k-N=CmU{^Hs(zXjH-%oC&Ko;d7x%&!-uFjjE+iCWi$bXF zW|lk1hLUea7~I4*_m=GhGB;6hnS1KB6Kj*=D|~u%`EaT~@50~oLZ~Yn6ZXxmjY45Q zC^1}avjFCX)U+vkbiW%{2AIl4F*m zJxdTCci@gp35-I7(xS$2E@4(aTG0`B#@L8Bdg{vM1%+f0f=_IEj21~8Iml_8(k<FM59oociYfluqs=Wl1af@j-d^svIBMk8%b z^lNQt=XX8gRsVuFP6J~vu+~R4X2C|?uEpQoL@VYC*5qGs<- zrbg)^=TC+lR!lVXyh79>P5*HP9KKA9RnR%>l!2uv_V?9!MoBQNg0m_r2D#x@DM*O>V8GLXQ6Mdzt`t$iEjN-d6+kI@tJDvNA89?QWcdhE>t$yUuycF|1BqsCFcU*?U*Q|4;!%;a#PAOTxpEL7-JPjC;Q_Q>9_{U8|sBJSBz&KCPF z6Z3Hy(P~K5f4?$2!sG zT{`i0BPcvzxWoF76=sFNSDBUbj^dbYCWZiZSxQ-Fph0hO{=7QtN~f;)*G(|AZ+BN- zsbA7Jmebw8k-s5tkFK)-hDRgGZBo0NG;DV`Q0e%Dr|O7k)p6}2bGPGPApn;D{Nqe| zy#{?yO4Bz%aa^KDW~CJ4Doc48JkZSl!1c@Ew<(4AL0|N7PK_0~lE;pWZ+X{U#Rm># z8J6UCuP19cj?|Q^mk{m<#OP{Do&oc1UZLX<4u6elWYb*bb#n4w@M&@hQ>$OFTYZM@ z-|h3UN6;*Qkn|Rp)9|YA(DhJbOOcdJliZHbiM%Bq86pCvicVL+sRp}StlXs}MBvHf zm&&kQUFMZ*=bMqkBrQs7pqeOd4u7SV1i~r(P}b;cB@+O^lbgLdly8bnDN*@NH#n-M z9n+jF|I1OiwevbD_|vx5Bo#j%A1d&G@74To4UUyb5soQ$yh{H9?n5QTW;VMtFARUm zimqXZ>*hF6)pMtULJGsdl35FXuuvt)o^#5i%!MP^{$({Lc>MF56=ks$x(}`G+>Xu` zRbUlI#euz60`JIP%sC}ZrptLoT>ngH!Em#e+{JZt#%lj9E}MpkTy~m|fDJ7QkFD24 z^T40Vt4kYUR3X6x6^8g{IMI{pWIkZie(PURUGwmL$^HlgZvi)Y;|!vQ;G$;|g``pW z90kMW5Z8sTfv{XU@XT&oKcf(I65*@g$U@Zi^VzMpzeOAM9cU*9n^O@|m|~-sZ=-F* z8-OEyLjn%6OI{gOGa7@@oI`<(Lax7Zj=An7{y^Z|6|KkYhWVS)jqu#sr&V62N-9%oA;-mnKug@->t zFrlnwe#um-lR_K?u-C+yqpGT6#KeevQ@;7`#u?O*taEuD`mU>Q2rnM<5ao^ST-guK zYvE?UnA*cvHr}Tj;{@VQB516L34K4Md8zSHEj_{ayumOg->hm z%$(_mJdy!fE7hq~^|JX{`lpQ8R^$?7sZwY{5us`K@=*2tj&uonu%_Tg-lQ#Q zkCO~d_he0OHUIO9cSik|fAm1-E~MSZXDL`&Tt5tkM#oC`oPc_X>v|O$CI0zSE{LN> z47mXd$L1g&UX5I;mvq9Z$e4YTqAgzm2(cKjT~FcTsm}wd8FCj1uKsC=xC?{{33#aC zfy*XyO?tl}YFsN&aIL zhvsP^A;jK1BZKLoGSn&$zIjjIa(H9rwz!TR?`Hd5$n@zRHEksJLN~cI`8bQ#Qg!D*P%$E&Wt43c-`dPh`x_XNXtC9j zL{N=m6LbAhbZxt+>=`(S{VXe7(CRDytiMZ|rM0NuHeIb5C38llRQ4R;u0T5(o#Xj4 zT{7Zphn7;EFc#>(<<<{AY|-1V(M=L!cVHu2Ms|D#H8nY(l$Ga&Ts&pr``*_)3B_Er zqHO3nWAeT5LxR%C377rPs)db>t2~7+`F|DL`?g10`!MuDHC7ei&4FUY;WPYixa@F?BwB@3EIm!-GESv^7q793RXx zl0Z|X7w2ad`9FV7bH1kZik=xw>0d8sppEzs;zzkd-jc0|49QbdhD^}jV65K9}umsT;ItE$=}CLGefLPhr= zCS;^uUVzHvtmto`pSs%jhd)X?4@okO_&RA(NCiA$<4-!cK$jZLKN5Q+*^tujLwDOp z!wUB!0cfS*Y8KA+e+rf7O3MU;Y41KdHO|blb8*vH$e}Vgv1f)s()v6ADcTni8?ppS z0$KQrzUfg%rUOJNJT5$S$=$`q;&|i+4pqhsp8s;miWW zf@}W1z<)LBC@;OFj5>j&Yy}jJIsBW(#<+ruV0Bmg;-np# zF#)c+;MaO%GJ9WeysEWYW5dLH!7b?Tk1kmu#UCtsZd!C()0;(?bbdDoaZZV)C>=`# zRS}@l?0j@)&0KrF)2F#46ov6nA-EJC_BCU7kR&92fk10ls1VOWMV=YQ4!!Vz__0UZ z#nX=59GiCL=nBfWXgDG?Id=YE9G(gYZix~AT{cfp-r@4s+ZI1}yv3>**i(J|va{JJZgbOdRZEIZE?#h6quqVB;uF`$?kcDdnT33)KCu1Ye)KPb*ju^BhX2z z7ZRMODJr3n-Y3vzkdd*@e^L;ZVSd23O`57(P`zZXsKsnRqXYExY@JW;KlD+X~ZLH{>Vf z*J@b9R4-%Qhkemu7MtkbN~ zJ}8vY5-2`r32`*hX?R)Ux3kz{gyGm33kjLoJwSi@FWRQoaoc&%2TP#y@tvMNK5bk& z6`vVvVlJpa@d-||tJ7=6a%xRZ_~ht4fwbcUU;po>BR#E4=20x30n%Cf-op&!wiXaM z6mSB@@-^DF31rOr9nUL5oK`?Uik!Y7)PCn9q4t*h7H0wnaUFWUq(%B`PGG_(NyHZ% zO?s3fc<{Rz*wJ2ns;?xK94iY!%CZmJ8XiBEpk3^>2jru_tKZda8frj-3Wdu& zSYM17!D*#fb7=;!4|99Wy4R}*@j0WoceM5!^SfSAEwz(j*hPrZbgffhbP-Ho+Q5?3Pu0&QfZA_LX)2Eb{d(xks=Z@AC3$L$k`ZpaBcXKO=gs+v|K5vht@u} z<3y25E@wuhS2v#-9dK|{E(?sqb_Ajl20Hnge?_qnt_h~i>zMB8H=D#(8{t?^opcred|DD0CZ-ywKQoKwJIrO*p6Qg_#qh0rR zHt9YDlH*)nF$csPNEI^vJog%dbbb2EfXPuA&<=Np_GgTo%5vl=L$%A|ug*QEl#Ht! z&@f4vk1z2JnhWH0*=4Aka-ALjfdI}`_~=N!Y+`?c`M2DO>3@(VwOoI_rrg5LZ_+mR z_2b`TV%-4Q#>)Vfz^(|IRtU_wXN=EUCCQo}*B9#_l6Qgo2NP-H>FMaojGg{Jj?O)h z>HYuX-87FaL@dDhd$gB8iRol1t<+{yOz z)poa5hTPCL(}~(f^&)=R68X=*KjQYr+J5<1MC5MK=r+;izlRY^4d&~htVQElfU z1D0u2Xf18@{a4KnRAKcT*Q#MVxI_&k*V|gC+dgq6ofP0Fzt(uY{+Mh4f=?)>*0lU` z8TRTQ6ze}O3)>o4%bNn6A$pGXU2;PgO}ix>9zX(?O0)XUNQ?MW z?bSUqtBPMF#lHi?np3I$pF#Zy3|$jH*82b~@Ym{}_T2lv7|S(~LHc&8+0D3{@G@bz z=rcMoFScsR`bU3!W7lee`Q@)O`-5V?SQuirTsZu4j6DncM@orfGu#`~jmiGZJBx^4 z@R!F`GS4EwDuG|L7KsobABIP+s?|w3Ep7B>X6H;jUIc#e!jUb_>-j!3%SV=OMOgN$ zs;uU8$A-_8EhM~VY;Vc&2@opvDS)8P(_S?-==zAI!GaUw zCV3vWHbIvf=fP|Pk@vq9uvYxs{@6REcte|kj+mg0{!EZ4#As|`S&h;+7WU~g`ifC;#G^K1&r!mtej@bIPw$l94$DB;M zSO}?YmY;7ral9h;RwSsu5QGC9mlh!GAOeaM`0lG5t83{0mv*~vj&GH*eUX#Z4=X~W zTajl8HvKhppEO;y#T&ZZ5+O0@``cvymzNvJb^(RNb5#zyG^$g;^b}$EZH~UK&-<~F zYvp0IF9En^45Zjv?Cg;q3_eM4Q4|v2O3orfno}JVKMW!CXjjM}h5|YrjcYtAHn}Xi z9z?SjEkKjnU@krLhaDV&oeoC4t2G*#?>{t1GiBp#F6tKtJ$r6H3GsiUm>isHSm(Yc z%Sz&B!l1=~y|Qp@YcK zjsZy4rpsGS@BP(P^OW{{HNIX7gWvn)m@)LSpXH5$a~G^r?|u?zePv}(H5GUsGd?uN zu?Kkcgk#x~6l=k>{dM0)@teXvzzMO!p`u&8cP4`9q4n4eA8Tcx&ymak5N%8Y@3fks z#wNRPXYF7a3!0)D>Fg`{bkKT?SW|KOO)RtVm zj&D(RssLmytqQhL>$oNu0I&5Lyf~)h*bX6ZRTo9OZ)wR4#%RJieq3GyMeIVBx-k?y zpF-E!aP#i$rUw+nRFmZ$qYV9}DXuk-btx;3_r*nf-5D{#7^a_ViBp4XjPqn4!3dDh z6UuwhwW<{fk{C0U0mfa$|674eO0|#xsJDI&cmX!zVDJXCFnQPt0V2}rJ*}cv;v_> zW+~H5F@Gb^q7T? znb(5@mN!AdcJ&!FIoA_PiZGI@!uN>Kb-FLs$p{py6&pF|0*;<5 zIs3*pEk=vJ27r}_USW5BSPGh`l>%0WkJX0aJngd(-+a`}n}86FiWLo&%-~>wm)hgiOw^D?dUQS(Negp+k{T9FAx`78&2l#?cWOqrO`f3(DMnZ+byg` zGpKwL?%i7Iy@rv+v316vV|q zk&1S>ZwhL)R@)rSyp9f;xY_z3s=f$d5?ZhPSM*qC37CdUvy0EI(X##>1cpd^u?H40 z_KcQzfe-9tPKufxIv|hM4$*yX@!r~WfNNpps%v^jvURN5bVjex{=Z-8q6m3^D)&A) zs6N#yxfH>Ye_kRWI@7ZRZJQ1tXOs|bEld|Y-VxEj?Rit5BdX5s= zF-H8S8UM7*r5LE>VM`Ks%OSC#2Y4{y6>Yc5H$MNy^kkx^taa^eIFJg)z{(hnbfYKc zJp2@*_2UZzK>B2EP9q;VN0a&b0(?!8#884$ZHhiX(<=<{bubDI$Jg=zK^5Z}o0S8c z$al@-^1aSu^Twl{>AD||tuZwJpmGEzr{`b+b6z9O87xRX2z+9Q%W6b$@SDC3lnwn& z*iPsf^w`fB)15R&DUimZF5l24%QX2xQ(UW?Lfe;TJ4@u~eA~x*Lj_bG1oGRHXY@_* z>)_T;Zycdo529UlwVeX@K4f;xV>y-Il#skU8I)0r_)=i&e@O|^| z8dF0#Z~CJ57LnrwK${7(KKHLQ50n<*2?l42{y{XYbidqcaZ;sPiUSNB(%7e?U%_+; z3Qdh{ibo_h|0U3ta(GadXja*@7TlbIMO4Uh_#r#Xj0+uSRDXrQ5~=yQ7X%Gk;vI za9^!`E4RzTXb35wBLHEU{@_izHFkkls`c+Otc$&LhT3c9opi-p{pW3Sc`- zb8T$NU@4)r(ezk!Tb!aWxGRgL9h$L@FHOB%5ONaHQt+=7?~K~`{&mV!5iRxkmWA0OXb#4bM@vr&R|E(}YC)935syLTJzs-M3!#P8?+%hLv%*I6pzYd5gKSuXQ6EfUyH zhxOwNPXB z(4_XV5y#xw>z(xtET=|~1OYDkyfLVZnomT=$vRP2ynb!7D!XZ)5Fe0VGw5hZ-|5=n zV!s3r%3r#O_lzS@`BS44I=LF>-P`35NIonJ_r#~s{N5PD|4F1RaK(B<$8<(M-cJ2N z1$|s_^}fK!rzc;lFEhhmEabo5Yr5vPt$BmBfFbD!VOywYLiAmZ3G)TGAZ`Q4)Xf+R7s=F9jD8XG}HQ?e{dA`ckN@%fyxbHpuT+Jm- z;cp-{_>DL#(e|G$zXch1ZELeb5WV}Ijx*nJTf`~SJc-xuCl8yJ(3^)SN@;DBdm*f@ z5aI-^6d`qUINW|$+a8iXn!*6*u2I}TkpIP?uOd_No1VKt35#Mul@7%wM|#6M9N#AK2BWaD=f`0$YGi*R z=E4!2rlx|y#LOQi|2S}JNzUAPwfD8zVz5D9d794EsQY2d9TVFo0*?a;kmQcOV-1eO18?bKfH zAt@_+9-E+Po0dqrHG7@V9uF_MoGm2h$bh$mT`7H}5w!>5qy+F#H9_6KKo5Zj-0FC& z#yR!r&@!AyOn(X8H?a#mEcZtMfXiB5%ch}gvG*-y|AvuulXdDd3W`V2Txtth2(PgG zH$aOm^;OJ`hGX@+^f~IrlyIw%i?1p6U}<&n++CmL&$Y6-Q!pCGR4$?`jXI>t31HVJXFXugb2uH;3g%Z@ER&tNF#@*Rw9il?xR z=OY+x0JeoLWV9Xv;h#{1ThDe1%Gg)doq*y*|L|}+3WDnsKz5#a<4YMTX;*M1x3*v8 zxX1k|q?3QTZRbyy;0=?NcUQ|;9dOKZ80!$vXOmX5(S;U1fyMYz_9AW!6e~770SsC4 zoQB2Uzy|&5k$q!{)g>j(%3a?k($$7tb~|)v0K9;LvK8Y>Jt_Ias;Qf*5pi>BH+u^- zDW1-pyT)3Qs+^-A9UfD{y;d{;m!Xpc5S>E|tdC2b806$nF|ZzB2C#NFan2(HXHN@y zgT9N-4r^aNF$N%gE;h*TQ(baJufqhsEL zSelhJ=LbFMhHMlUV6+uDQ@c)Y$wVFPSkD3FF0XC2W~avzB~_FFW0t)QTZ;ZL{Fg*) z=8pwi10OHmoG#Qdwt-)i{WbX}+>4l!{UNrWak+6_OORGH{9!)1=-AaN3({9M~WM36l9uu`RUrC3nu z@2tCb-^8o>hz0E+#h5fdj;W$3%;*`LVYtjyFHWPb=AN8Ou7x5}h`v*_kLa?cXri9mLi@&X! zGOLYB1j{mnfAimmZ168b%S_JVwYf-;7 z9wjpU`N2k*Z({M~tExY?r9}3<8gQncXMu^BM?*%HHxh(Ts}46JyB=dVX0?0S4K1aO zJ&mnV2kBJz&8!=pfylWcG%K2iK>}Bf$y#D0x34kf7$pdjASn&Le16V`tHkwwWR4=u>&i zMeHWX13xF)8+&87*sfBP1Y;w!x^@zeRcBYHoN`rbjLCYqh>eCDruR$%;3=ZyH-EQ` z223)N+@n1{C-Qc*Q%`2~PL+~_Jb3RfK4@qODB{<+LJ`7kbZ_N^4(xrAKxc1Z;h?bKm=#{@dR6(LUt6 zpS}bQv7umrsG(Z9*hE9MI6fbf2E@LfG#+OuIs-NaELj9@eyQR9tYcnhKx+`-|^S(-Pz`<|AZeq9uChjhk zUCkT8^wp!Y{=_ZOX@Pp(<&^zAB*VhsK8 z)B7Ocu-Ou`83(jEuSI+o2Z01HVazkEAQ#Q zM@CA?W7odT#;ynGH#8|Q=P>W4*4JRxl_eMLj*P{nU^}=#3QhKk_{SFf*NKkUCgqPv z&`m@%yoxALyYkFS_A4hD#ID~Ks;M}#HVW{b=7B*e?RgYKtAP5ay{wu3L!1lUt%WZ7 zck}G;fgqUAOmLxkqH*E(V^%`z->sTdHplNqYf$S8x~px=j2y zF-)BYbEhkR9a`8t2+l!HoaA!?)UPxNdgQKbr@9U$^P6<$#6VMawQ#4_6}8caTk zWB;L{GgfK_grXBJ4>k}CC<8QfJ!z8-{rMr=^_(o^91D_-7|rRQ2QBt=KP5@0_J1o5 z3j$`LQtZOyMzhyXn_AZ970@_@m!bJoOkJ&i{y}yNo=z^!?pVY%y6>0M9Fao_jgv9d;YtV^taj+TrKj zr#n|85QF*$r6BlQqi>CgkGX&f#)f|pd@9!{4jyycKZ$t|Zhm%evO%i|G(&;?X}22~Q~gwh(;8GvCkJ8&UCkA2 z?t6oP#-8x9Dd(RS7erziqH2E04Dpz6{{Z2W*d?s-QD1+b%*z!aYI;;GTeJ%YwN(mA zcqp^*^0q{w?f3IngCUSfuot|lwsceD`fmR&vM`{KBCJ6O>uT3T%BN`$L2c7qU4xF! zRjy@ZB%X`8i{;ct&YG2#CxvgD36T}+kI-N7eNJ;Oyd_S9SC5!rd?SHrfKmbdIZ z)8W$+u5E7gMTl)#gj$ZTaxFNk^~{78rM%~|gUQ*vsDmy8M|%Qo!ye1t~yMM^(If)(M({|q)~fYa&B zT3{RJT|QSpE_EKD%L5d7KBET>HOn3izh{AQAG+dW)L!Rl>uHLO#390&H}JHAx(hnR znxFzMm8kDVd(n+4A|+~1>dcI5O2A)KAV6XGZ=7`Rqv+{^QPv*jq^QFwrr?K)d=Ss@oX0qtkfdo(1BU)()L+n z1RLplL~O$bMzD{Hvi{`iV5JwGZ(+IHzBL0)Fc=j(FMPk_z60eUrc)a|7MyRD5uBkx z8}i~UPAp2>p|#RH&dvLeylC{W9s3{o%+H}8Sgo`r4H29mt_V3Gt$ z1R1;qOmDaWlLTW^3W>gbi}v6IrM}9SXezke z*dw-A+O{^xDPFg~kh>?D(RJmSGkm0o@6rCBmhfo0c$+wnfpAA7iO` z?ctS)Gu+FdPrkUuTe&JcK{__GCf_>ZPe}uOqEGi>;EVZSS$aD@e&?kdlZiOHd}WYB zTZMh3BY5#c3iL0&I)4`=N^1+pFPjN6c_)7b%&;ZEZIOygifj1+8X@a|GfDkce*=8i96(2Q{~F!AivC}bxCYf5Y5O$%Y!gP5aQU(kT^Q_VJ1)Wu_t z1OO7~HOn;g!}0L3((lz)cz0UhHlS#|u{q)rwcCKvULquO2WzfQoeYeJmfS%ayKB*u z;s&PP4NW_Xw+belma-$9#c1)$1_x(IRgl?#(%j`Zf}NTzWThrq03Ml_ji+iq%h00_ zt3FE8_y;w!IKVf#>vpA*W?}lX?m}%tjBT=Qu545W+nj^fk4I6@grp+|_W{el*F;-) zw3%}n31d!z6rSbkuc9q@;nMev?B3+jzb0+3_iEJPF3O*(&|jf*KCV@Z|A4u9`;QA_ zKb`iT_44+o8D5!)eSgj8YIW>^NVmLbM_C2I-JxLY640{AV+l(|s2EwV9Sk6oVXm4J z>>8{&MFuGkT9@=Z(C)gdM`V0yeAwvNHp)q>Gl4wDR));aX2GM$(K-iBq5CWz*$&IN zHl6onr6uaxZ_>1}B}(N6wIF z6R7;;FD!$SCEo=CfAtlY4w-T1dfPnUvt|Dp_@6S<1~8smRD zgG_hTxP0)x_0vE08^oUmhS>Er>LSwx z560n#eMVid1{<3NL+{|9<1_1Cf41L#ruzG^a!CzQ#f_$zO!hI2XIjZ&2i%4g0`P_+ zFU1E|yIAMS&4E5(cRfWC`Y8SwY`Lrx{Y|pHedcV#01XpJ7SI(Uzy{M&&2=rn-pi>2 zFz!WcNqd0Gt@~Y~B$V1|!A@|KZ>SDh$S>Pk29O1}Fy3(kH7wc?r#j_hlz=dl_VOyK zF*I+A6)#er@}nhp=!c*967Po#S;HdbX(B}u!q=*J-8ibZ+v4+AZh+d#Llps=a&6(M zJC#NBO#caoXpjMpw!atueZmdDc8iR`gpeHAk64YsjqP7oIe1m@M>u>w4#YW0kt(*W z>1wEl;?-61IxtZ?bLXDeVxJ83JhXg6)*?0jw_;eu7X_I4RcbR|8Gij#YzlgKHFBEr zXR#Ivs|r!DeenTpBzHlUKDRhtvf!aLsq4r|Zhmw7P|i8(^<0ptdliD?YdfNr!fLuo zY*q6KQ~q%!$?p~~uD>`euklwaeEULlD3WV-?ZC zn->mbQ&7^P<@i}|v)X&5hH+M}QdojZpjz8%OZZ?5%tp=$w^7>q33#21K4ZmX$jPqa zbDlY3Oy1BS^HO*UvfQ6lOhHsx7ig^{6Yt*NQm%&J_hJTnS&)w4T^%a17ejD+^OuH2 zlfCl*E!*kEM^H?T8kQw_I*{)@)h;FT5ouJ6k^!T<^q!oY-AFgYV&G#TZROAtv65l@ z>7pVLFsZ1<&+Mva=IKetMdoklB|{#5)vN@shz z|JNsPGE@`cqL3_TQ_0q;@PrPAwqY$ZIE3XLI2_!Ou&Z|5QJO~`qa+EquFQ{5V-qyM z^87$i=zZuZqm8m?^x6F=EtlkD^#^-yL3gonT-O}}8loZJ(H$C;R!EFaP~f64fJ$8s zOAAzexm^A@df3naoNX2CQAdZXi|FC^w}#hq$;Df$kZZ!*fM4hvs%E+|FMnE1uYh9c zB)9*$Cv|Xq{%49jndfdB*@$g)==*Xg6Ew&-mcP6b_Xpj^+;!q2&NthdN{#Jj+Ev$w zMCn5&Ffksc{d>qw`?f+Ulp`%y?F%6tKAC~nu9%E>3Mtz+I6W&zx_Ap45w)4)E;&PY zF=}Zi1XIMFNT7+vdAr8!vHTqw1THe~cXWyh}%ZKhW5>DDlTq9Uhq*u`dQ1XHd_9WK|Y_N*u?RHTfU$ z{`6Hy+;rf2bGd2Lt*Zk?5G^$5e3X09zpt^Gzj+AN&mx?#?a6vI$>o&i++<6PPYdnl zroTuxAk}%5!svvDGQbY-+q|%NMgO^FvzD=!vzDaP(}^t`HQb=F0+6eQewo=Y#Hp!W zZSOtLVcRdRn)|`OjBR&sMpTt!cQCh{@edvXS}c_Rq{-tDUOu`5nsbiVGDL??wK!$XCT1~jvwXyH4B`@eVTbVI5VNs?jI+*b7L%i8$ChBToa|$ z)NIdY!{iQfy%dut@bavp=tHc10im2wDU{%6*1uXzvPE+_*zL+at7r6b&LzeQDr=XL z)*$KF*`{9B?SG~D6|hYgrxcTG9KvPoAgD&=SI>In0lAPvXRJ;7t_h+tKo=?!Q406I#k&eCg$ZNXo zc7XBKYA?8EMvd~??v6S-`Kh7+8`*g%3VXlQ7ejHph`{o$NQ2Q2l|GNJC*Ch?oG{c;I}8+h7MT z8~t9y@85@ChH-@H*w{kCc#N?WuV+%0|2TuizRAvMBngo=dEW4`ecJN3B&uH_M2k<#i~yM?Vi$?AhQ#ViDh^+Zfi2T z7{{g=yYx&1uZiuVTwXm}aKoX8o{D*n(_|-cWK=5Tnr>^*p~wcrnEK{BS1ww+9P z7<7nuQU(@47=nf-Fc#1D7;)JkG<3pR$^^5tSM_S{+_yR)E|X#BiB(kMDLE&|VgSwe zyTzR+izp&_|LDp~a}J!>*0uKSSDKRR)D^#A_j6;wiEyj}pNM1V2!RFh)|21cD1mza zTX75mue0nFL_9a(atQlx%K{1#p{y2oLZ>#@-U!_5XIF_{_&5YCVN=W75cOtjn}IF* z4|V6QI}R==6}y|PTOkB|O>0S-`t9Zn7rHrx;qd;U=fSKtl3K~Z9HUU-mAbq=487Ii z!eA7Z>hsh=i?J2^+5SFB@Ws7R|I5@oz^@t!Mr1}Mv+QCfQjNV;0cwVT3DVOj@rUvC z-iHuM?POitq5R}04P?=D_2lU)Y7bYrCpCCcHEQvY4077W>$%knzqm0V2&2pj*&8;p zH2+vf)N_yt8-T_j9wi&7sjdV~U-*t*bz;cm{NA`ZJZtILyK1&a%}d|9mEO@hX4x?^ zYR9k8>&9_7Iwdj-2-ssavh=!vvvRr*HL=T20Im5^xj#U5j#plAvb+^bS6>YffI*1y zTW1UxA%vJU!H&LYZqYLSSwv9VbbPQB-*2U9xXBKiCLFt%_SL!SiJak+-bwdR4zX*P zi1A|kr09#MQ*PY*;xI&~$(V$g-D0zL2oBT)S6M!&y{V}TK~a6wQ&sn9LlZAv$e)95 zdy!Q@@t{gRt>%Nxd-AAb8b}(Lv(xLp9L1*Ofpg3Gi!WVm(k;v7#6@U(k#3gC!J;pqG-M>UUautoD@gNCFq!rV-Xfa? zuRh#O=#xg*Ea4aiC&{({Y49;gX~+HtRe(*cx>(l^z)U2Mr`u+ZtMo_!&D_XH7plAe z51?2mg=_$BC)Z7?n2QbIm)d>9K0JHHq>UFHiJ-s6;+DN-O#MP?FdA)pxH)$q;w#ul zoV))w_qh0Wf)Ovl1;}*U?dMxcEslR*O5)o## zt+BN$qsY#mr1m&OH;;#X7RSs&3Ye$fRg9JQJU9)Idw;rOhVOr(nJw9@bNM)>>Lu+E zajKWHY>#Q#3=rMxVY;xXb$Kdwp}|$eke&KsnKyA#Ha7XMi=1zx8h8NqxiJ#nPyrp%n8R&p&+2L(pMcH zJzdi>B-wEUOm7LAWC@8ejcnMKt&v@T!EU*h8C1x+-ln;YLFPe#T!DcOuYMZ*k|9Nd zk4r#SL!C0Dwvq9_uC`_z42jyLO+ZMCVL*foWt9c78+lrtSNl(IxtFRy*C~D#rV!sp zl0Mnq=0?Z=fK;1khewo#@@06^xx2XrJy|nTT;tG%m2jE*PMw;^q4Gtr05a}q74g(> zDcz{?0*``poY4k=-TU1nV}ib|QL`B9I{AO>bC-*_SZjHo73JuA5miLI#y)ww z>xIb|HYvXWxyKQ`MjHTld}vLV5;K!{zOQiyeV3uFR`n-H_!jpgAMfSVTWXo?o}#`N z(v@{0lgV*Pc*0-LO$OS`t=Tl;aDl@HYv3z_s=0xP)+L_6>uiz*0+ZgEa~dU z0T^bM=O}AB^Azc#*BPev^>(m7V^?_hSPg+*t&7M|>qg-)#9NlQEoH0==vL=JJdIrw zoIN}75Cl7zO0`PGOo}DTI}`E@`#=%ECSpzdN{$DJ!1x&csCUsfsBVBLp+E@Hn{GdH zFIq0h$Gv}NG(jnJeF8DbP%uMl+yZZQ8NGoAij1&U;Z`+U%-gW~Oxee=t)ztfvpI)` z0DHxF!-IcyOhIB^dfNX_ql3+b;alf($Um*uDu3xGA#b!wXAK6aZ49olZ?3_h2NN_8 zh)4L6l*3NQz|ez(9~Gd}Ca(ondL$pjmgyJ6I=uU1i9k61eR2q%y3ivQvc=3buJ^wn zCp%A;@g0NNRPc(C&AAGmJk@3SVPfeDTYrkLFiV z8Q6>_58&qpKAH<^epu)B$35=9{zoxXh5PwC=|=FDKv(P!aRVtR=4Ft*{(sR(SVsg! zf=|-9#t0VUBs6;ooS(atMxZ>pJxB$o!#~I#7`*b>&1@#~f)L(P-h?a6XhYeW8=8+{ zZ)vN|mmFE4-~*m(Dt@l;+1r6Jk$U07cz?S0f3m1eLz;Py^w1DLA+&~gry@7#*6KHG zP%8>f!%e%=?i=N}L`t@VH>OECx1;}`%d<~e30fk}&$Xeo}5Pu9q8 zLhK1%k^}PbQ??UtK1CDwM|}noIWc*jyVxX5qs>p|4=aO-embD~FNa@F33LygDz#{V z&{D~2;m?`<$Gi~)613{OS@Oq<+XQ82ED1j2N+O5d%+y-SD{Ocht78P^is{hMj;{f0q5A4($xx?^cW?H0*4V&;;DJDBP%=JpLk{e^ug?b zh3941+z4MR$ESYFzh3?+B&Qz`q{+G^TTQ-00LNd!R< z8&~VurHM$8F+&hbU4lDc+Z7*5*wrH4tc_2=yolgM6t4MbF0!8|x!yUDIa|yS%WIlk z*0`y974AA7eOLK|IY!Bj$dkywvB(q#xnZ{1WgmG}O+SH5GTGypbni?zw*bqo9xaC? zI!(!xP*f{(r>W@qN|L$=QFdqWjs#Ru`}o4hWjkEscnD?yKy0=p2{vEh#nD@EGE)5a zG@XYeh+T-!z~ZC+Wcv&Z65!c)BT7mNXeqQ*T)V~!Uh5VlYkMt&t`zv!_vghT0{{br zKH{y={3;ug_%6GJpW7`vd430-iUhE{w+AvE5<|C9?}MpdJiKGv_hys?3_oB-4NmA! zr{aZk`J9^{`tNwHt02C!?j1#Xqlz#K#=1DpwO6lH@4ADhwly|oPkAQxVTVsaY<20m z1K;JYoJU)V>o2CXZ>~3GEQ0qRx_Dn9o_`4B(P5Y?YG&;hkbt8~bj!3MNi7!F$yoUK z1G>H`I_R@D^HS_2k-aZKutja-dxE%O{P+@7TCt`L&nos7L0@Lo#=Yb@qgkYm07rZp z@9BB!otrsG*W{w`I?fe&0H-$I*|Ef8Rr;K-2)pI}Cf_20LyH#ep&bIuwUn!2o>#jE z-fQKJqkBaDTcXtI19#NNs_&}Z`&dAmQ0}3Wv!>2zmQCj(fw9v6>|mUU|L3}=@j|X* zZFRn6|6LAz2k`5?#hGbsSV!1hw4#d~FfAplnj1BwC{K}FC(0KosN7|srM`~Y8=5+OKn-*4`*`2_GcCSgeA?);=Xs3%17LAEU2s)^ z#HR5HzaPZh>Jc54kw=;0*xQkB~L3L{Fz@m9$@ME{Ze)X+|Ib@52*7 zU3Ei)@D1CIY^?d)vMrasUZjNFyMfehL7a>9y~10Xx<1 zKP~pFE%%T*&Ct7mdz4>rXEVl)*K6IX7{i-Qt(&|YE5nPYobIM-i8j9997g2V7i4k$ zSrlk~VRg(Vo#Gn1;5Qd5?X&>8ih$aiFXkzK#BryIH~Z@0GYrAfQw%^Wse0sY8KP7E zx8iJVsw-?dZASu#R|koVnS+w&n7y37KJ&*Vde607&z&K3CJm3ejF+GJxcjVYyX~!oOyaTei zr_f;Tv%FI%e5D<3+-Xe4G&I)zT&i@5(K!*^F(;4`jwAQ0pT%;jWB)xcXfMJ)of=LQ z2N;?F(XWP@R~6xZ`ymwiheB;tu2Q?w{(gnbd*HDqx=s@R%l@=pb7KoBZQ!mE4Kol> z09Vwdng~K%JlzYx$QK;O!|iPQ4sKSN@LtaI0fdGJ1S`WGHPjBUHZBVSj_$)I$z!zX z_e{70PizWbhH^lm1n`j7_H(99iE3B-tFkeOkh*=j?wfPysN3mjVgV|zur*`b`)x?* z@EuZ~hi3sEx43T}p-14KheCl6t>e}dJUdC0lq=`P+?O8uQ~wH)F_;%nhn35u$i1G>fZVfIq;RO9&pmI1LR+2+KqAx(IxyXB?4XWgkMU$B| zIX}Dc8a*=7px?c}r)&;w1d`hktH(N3TdM}B7^_=O<|n8OAC@~gC*YLd|5glH`7AQR zebnz=-%^b4E-Md|6- zF%~ZtgotTuJT6~y|Ni9JFRZ$LDhy5L&H%eDp}Mueveghy z3sPJGm$PIhi$Rsgd0LUqBm9~o+w$z^G3izI%lHvo!Oj>R+6R<2)AXhbM!OLSVNv+C zk9`_P{`)Ub*yC#sQw*|Og(!dp%zu?6Xz+`8CUv$$6?7~@V-sMAJ+!0#yJT=OegXe!rNbo@Wl5IqbA(u(g0ti7|+~(T+N|9i&0v zkrj@wS2SfeEr_%%kl>nyb?YMv<8?N}1IT?Is(Tg17+bSMMu44l2y)^t$y~#GVKM6YXxe-9u><`;pIqy`wYP0}RO1cN} zT@4Ux1YQ@p7NKb11UsH4>shWozsc=I5O9+iYqm87X+1#kTn{l;We_A3WVOD3=gRnK zACtAW;=`^mFB9`!pK@-L{56VwQ8w_fcTSe90WnCmH=n>HZsI<6D7 zyA`2Cwdna`950y_IgRS{}BIX0>)Fa!Xs_pRoKn-G{C!lETE? zaJ#h-#C(l?vd8XR?Rj$qv}eJ1Bgd7dWzA+)6O_b2cj0J`3Aeb28)wBK$Qh3Cn7o2j=3NS&iARa;vL)C6e<1a7Phy=J#)Eg1c7 zUeO2YM=KIfK+M?^SCN)SwdX$akE+LCd?2*wCCDGW4D&#Xm zLj})~)tawCp8S%v6c4Xfx!#&fZ`M=?rPp*%wppU39f1<<9cCvhnPx#r8`8%vuX_9? zWD>A+&jeqUcmI7NAIMEYV!>VbhXc;>fz7(Z=OYF6pB)I|Sx;8zW)2_x zlRSholjMI{&s82ycwcm3hkX*9=&IN8<5uHt4%fm)g11eUxUYIl#WJo;nXyZRA8#8p z-SAkTfL(zcU8J3&a%Lk{DV)UQ*H79$mT-!1vtChjga|~_3f8gNOpNn8d>*O*Z}@#P zdUH|}4Wr<_nS7`3ctm^wM2wUMggXaOW_Adg0CHaU*0*Kl;J_=PJ-Bk!fzJ)F4^Rxq z-L`W<|L{QWD*U3|^{rpE-qX;pJ|Ny@2m%(+t5$tg)>4nr!ZOxr?+V(V}t=MWl6Iopie zVH<{3&SvB=#msWpirU7+>>j&+?|%RHXb+El_WrzI*Xz2T*Hf{3;Ch!S_OvrLH;9>d zCZVnSIJ*Pbsdx4LDVC%{an}$Bj)OXjhK)HYdjAW}l7J50sNDU`%_nj$QEhdoWTNFm zR>}1WD&AVPA18gYR}2u{&YCap&+uU+bxwn4YEBtLsTcp83#j(HPtXF6ru(iVoCFwv za-~Q!`xu#m1Z2gBt&jXhvt|6VHt0_&){Mm)PI}ikKUgv=)FjJU_e*FkXe%SRK1Nd-p0lpXpjUbpG()zcR+fU_KQQ1ljdUo3Q*8jda&Ju>B!T+W#GL$WTyX=T?A$(%lD&e5T3 zVtJ~GhT$+AW37QfvwoK;aWjil3`usT`}gk#V>Z5tLE5WN^#N~{YPbx$&y9xmQ9(tT(EDD;YGcJ1nIQ8`bxfRv|8JRs_Y~2*SZ=bxZzC@pDhbN*6n@Yl0RD1q{eel8p`V5Y zppuy!7%5~#dOyDM-#SrWLG1aO>Mh{d-0vl|Y@dn@w&u0bT0y`ff%{S!662HVTho7} zO@#5z6}p7+%9T8HLaq?2$pY3Qg3x%_h~N60tcZWV$2>A^3DBUSELiV$ zAs?lS+kPiIoY4^YnMfL{NXvAUX?W)prw{8?ys+>Vnp_#Nxaxmw5gQ&3<7J;XAk^^* zve@6hfJkm+dPJ%xXGi$m5xYw3F7^8-HnW0m*5!%3>i$Niu27s}rt9SzG$ZZ0x`ZOW z>`**~wZ_3Y(8)zjUPF{_u}6rY*hLHDfWs_W(M-JCDs5fv^`;qh#EYq8 z*hDNER8>b)VE@{!nLzzwErNI{$qlr)K}NuY0V7FO18h+S_p)r*?<5!zP;mxvnRY$BM9|)+ ztv@Q+ia!8Q=`lt@#_>|hSHd42Ri2&RXzTt@n1$71@QAy*)uQDzmmq8y4Fx~6T>?ra zrr?Yw&Q_mfYNK@6dtyUiiEj0vz6qMocGj!hT_h@{SaMeFM1!_3Jj6%~R4$kA)Yb9r zN}uYVAaszb-6KTKEICE(1VewpRJe*J3(RUPXYy(!SAn9o4DVu-N6%={*iz;&NB`?s z+uyGK6f3{N?AL_}_xhF(a=_JoAl9C~@3v|bt&L`KvD}Ce_3cC20Vxa2X#O#iRNr8+ z1`X8J`i-2sCCg0>BR^UgIE z1#xT1_(6XrM|2Dff%xIzwfCM!*94qQd`i9=slyW>mz$}@0So(q86&`5QC-?CMvrJV zZ*RGayTM0I!A5{W{3R5G@xmuy&wq*W$ukZu8URt%>M*%Mq2A8<#hqLMlNy8i$GijT z;yqbGEk6?UMv}mpKh#iW$~U>RGr0jh_>Wt6TrVir+{=?Kx?U`9ZFpr~0QSoLXTMj> z=*R*lKn*_@f?0|jUmQ#mbXjfc61e*B}3J)Y{ca0iYJbyUp zVKv`oW_$qBTji)*l@}`7D<)TteU`IZj^BM{&Q(Q^TRaE`*!!2`46am(-GlB@bhS`vxHNLDiDkLY1GX^1!3;akB$z)}J0(4< zFV!9^3p(N%TJ%m6C?4QYtx1ahrt0yen}_n^u;Df{k-M*NJb`K!2>Tr$ zQuZs!P|F1C`U7e&Ybzab8)|PZZI0Xz`JN82Y)bJy*WUR{Fye_4_BG(uyPS$+1tIuX zF8HT+BQ;b$s@7Bjh?ZPLRK2@QAf)nPXJPzi&t(9yW|vjz+M%94$n_SzNBSqiEY4+y zgqy7`!Oj*}hyfK;&kt1S!eKM!ug!qixZ08E3YfU z4ddM%$%UYziLwH3PsJIxIR8cR=K5#w#%L2I5t|TIB)fjLk;Fx)-#fhGqV3`-TMEao zrcw|J8(PX+zVzD$>s(_<+hJ{B(l`>3i#k4!|4q~lE=*-a^it)36Vs2Ndf3RI@5dLJ zd({MN!)0X24zujoQ4!G{Y9Id$)Tb~NUq`>cX3g8N3VmdPj_>sW%X~p$xu&nKEUWO3 zs7%bveTYms5Fj}k}Z^z;&3h#oVqj)K2sVBtzxI!7P3Z7u(VE7yww+chit z`n63IJ$oR`uiH57Q?atE?kcp|pN5>LpR$0r>V5ZTuiA-SWs)+FEuZ{!o*n%9npq4n zfYS=P6c1+b%%p6syf&0Z?NO^S8Yt`Wxh$HOr1Fg2wzGcRGHea|95&l>*B3#s*W|x=gcq=&KCi7QGp+zt zl0zibvkxda3;uWoYu6hu+e|odSG+0+H%tavk7tvvf;X4K+^>Faqrgwf5W}lp`&x3u zfF0W9h*2~PWSy3B1fP4}!hVf+%a$zbbQ4}dfHy(tum~83oizPL=c51pRMky9mg*x9 z)Kil?Y+LR`AI1-S8`;GO`=dBz)BWC)W6Vr~P5%Aq#z2z0#<$+ixDkx6r}@8{0w~eQUqEcDbNu@tF zOP8v;uX-iEPgQLl`ngD%%34+f+sx%TOlMgzd(J!BLue)?dXWDuX5**+%%W6Td;8$CHtrZga~f^wz|{PE1!2+eySWw*}P??1t7kn$l!AD(|KF# zBK+&K6JH6x9s*&%)YAx$k78k)omvl>baZc2gG#-%t~5TKk_0y>g-c{h2acxn%}&Q$ zl#+-6!AGPIOr!WD9A?QU@*e8}8kCt>HV?#twW_yIU+MLOXmFb#m*;KVCS-ueCF<5%tGdsr_3(`ij3}1-6HEx zvukfr6Op;>RGB8pMDBD|tV6ejFw0UXThe%&!4;&4Hbc!@B3N8)$N4tTw+r<(7lZfw z+LZPMJ>uO+%8S0Mu4v7s$o_>5r7%s)$YE=PLs4CVeDU8Nbg?_F+44+D(CNbrX61KO z8Z=>zCv?kJka-}&{A52}gQ5faI=6(g0cy1Jk!YM1vv`Rw`yIwqJS>WT*5kZ*JvpIk znmY*}9=YFsbw>||4;6h9O!I(9Ms!Y!?PzZ>G56v2)1kRs;DJULc{lfiUH5wAK2#q% z!GEfY#%4F>1!wvF6b;`rV}lgmKRjKNj|iI3nd)T4$yghEHyAyTFNU`nA)-`r_aA-- zOEpNzEw8mvY>b|>@t5R=U1h0T$(FRAZk{4Olfd38bsvkKRYT&5ie9YE%(9lSX`ZCK z?Rm}Ms(oX$Xh#(ZY-kvj@Avf)wQB?tK;UotQH`VQJ%j+9plWrN)z+`{H6}j3CJnvl z_Bisc=nYpCn0@OrYLLYg;(e_GxbXUwCtRW3GvI$mgGkUK z#Z0px<-%ZT|EhObx%jQ?n@`8()_Cy0_V$ji(4j%yM-FtEw?M&GLcw071}*`QYLR-| zQ$9qGdA9BL@>I-wlSkTuY6KlK53>Y?cT|j`m`HOYVG{j)BM5$UF%;SFDFKD-)cu}xR8r|tU1D#F(WCl zf^&HxTRtF&6rRwlui@eHqoDi8psXOhxsCu!GeItA%w;g-_M)Eb*>wGn(zy+q6r-&YXb#C9@MDC=nlK9sr z<{O%a+?(9XqSMj@V{T2wfbFr3&TP6M3p(-ezjaVbP&8<+b3IG3p#qh#7CvnD<%Z1x zx{`IxQ z7$9-K+?ndvns%!(EadMISh>h_Npurp6Xx-25upKBgld*COsbvqIxB3*kJ;oNVyqVp z{X(Gci!$PG#dkM^M|}mz(eoA>w(Pt<)wXJdcH4|;k3(vs=Xh0BYToBkfdmVM{pdF8k<+TF zAwrYR&~wNnbGws~;dT7x>;b~=N;&h>QsVV`*Rl$KuAR%Tz+-bK}Lu@q=3C5YqO^>Z#e-}pm zF+%1(UEKCkHI3Zjz(!GB_Gin1eKi;lS6^WG=Y7{YkE2#MS8UP#OCuY?mI<%Mzt`0| zy!yU{zl%J4+rnS>dd@|qGL43Ja@#)^e#JH~I@=i<_pW2dlojUo`X}8CIS>h%SAaj+ z^s*c%Dr;<}Zlg@h(*`*sB_w(y51>#@$0^DX>Xq2I$lNMyBff4l_xs{0QvpB~ZvWX2 zfEh_T=P}?3IT2;}m&VuY%))y~r`XU*`n3tVgS3C-+2&Tw+1wnxBJ*LeMJz*nopJ@8 zu;O0_=(-`0E`y$lPV^b$gaVr*HW79?tcP40Hpg}!oh)j6$6=8z-#o$W8v5z z&PGuwIF)b#GXmr8tiUGSlNV$l_qv;bt|_=;kzALQ8dzhapfbf?HSS*;_@%Z+9A1a- zu+0_TaRumYt52prfF&?jQgcucob{bsK6!h{H$#m7a6cWxyE!X{hvB{+RSQDEf~={G z?FWQN6o9R|EACef74Z?n>y2zh4G>U-q(50U_yei3!Z-A@xK>OP=8N$y?0?Fm1Z>CK zI=2jsN-XC62s?rs_J@k9*f2cf5TDxuk1rANF1%)4*wi+tePYuendPP?YTRr)32wO; zC?giaV#_is1!joVHxBymbzc!Cser2SaF8gG+eXb%+Vh@G#d&qBE9s z91cBP+RA;siW1iy$Q(4b#)T;9Up*qp<*yH^w`Bkg_641Ga;`O+|!y~ zi8w)jWLd`=LA;Hmnkti&*dB9UR4H7gi-wN*aDCs>*ze>X!DA^tc`S+%0$v<+$UagO3TFf(LfaXvvGFXjU6J`QOWY7^Cj>^&mC*nMDY7m?XC}YR?iUEY)6c7^yXAA7OO=jd~ad@=`qQj zxtY*V!uaknVY=2oLzy2r-_{9$#|j%A#G#h?Q&Q%wX`OwknZQ4*i%+f9!+8A^XW=;~ zJg~G?4@{kc{ddIE8;7#2xbkdgSQ(vLbfHQ*>}lJOn_joxY>XV!*#i>(wm|*;s9O&` z9n7n#m)vW7S^FT7T((0S%BJXxU4=+IC6PN$XPh0eAK!Ia0^ec#j9qWm$8ozl z`i81Iy9hReii(SXo=^@tg_4j6YBzVpE_l(YK_&s#nzLtt)c1DEI^Fj)kZoe1?#fX^sgrCfVx1Q*uGaxXoc2DBV&Pdf zhjeDjP(tWdaLs&Bx>hB;aZ&eoF8K*~l(Qxr*!Me_+TwEkqV3L4XpdI{5$H%g?{m>( z>HnsCnz9}qjRIhvGZ!wh$wdAR_#ebV`9n_2%~as9AwwcFe6QDaDy{FWo+^lIcAKl`>o_jU$i6tEJlu#knXr(Ih`3m=~Eq zrwRtPrM+tYTs;thbkLI%?d0w@o2amRVc$wW%056B@rk;}9jpe0db<$5P?;X-c~svZ zd2bhJeFW6y*Oks94$}8!t^6cByW8-17uQ30GYaQ=Pt{a{@nbDQS<1$}oTFo%yh``= zw;sf%P6!((&D z2xLos+Y(^wUsi|^u7Gzaoh$ZGsk3Z~iT^|vf-3~nY_E8X0|Fb&kw(->pO4PK1%#X{ z@9wzuL-m!R#tRqGC}`bg+|UWs7%aNqs^8#_;a?|*TqDpzkI6J;hp0RA8@aYGsfaNu z2G&B^klwoQi@qY{1PYfcg!b1aU7fe!jf%m~$S2l~-3hRKi_s&cqpf6At(8*vg5lcd zy6do=8gh^Kc@+4qrm?XyI_+NTnuJ%;)^pfI{bPY~_ zb1uY`DP^82KPgc8E3nXPFC=RYNWlN@2z2jAEG4~}M@Wsbs?a z7g@pP*&)FDNcKC-=yfQNosRsAu7#}?m)kF{ zzuR|a|0r;fM1#!Dt@`RZ(ce16Ka{d6cvA<48qWYd#%U^RPXR!X4R?K)?-Om<9Jr~ z0C{nJlK6Q&i4x6es#}?61z;a67^(8TSdB<{tV(uxmXbf4dBHA#);rfkI#d)7G=Dz? zC(N#?~O1I5WM@_~t*$f=ql_ z|Eug`0p3+ZxwX21);gLw-~SfVzUFg{d@hpr@4&8;R;>)z5Jzk?g&5STB+*(Y29!D)~BHCY?unfzlN2lxe&?joK@{L>cA8@n^-_qJhBN3MA)0RwPn>;B^*^~fS zU$|V9)SQqooMT^MGsYr+ahOzw*=uBO%-3>zd(wxsszVL3d1@uP66?j|{!qHA@X4MEzob+-*IjI?%ee8(;^oJ<|+$QF*Q|(FXvbdG4RYTb)!z+uG2zF&;ikFbP_0`N}e$omkY7t!ZV?K%G#Qxp=8i;Ew>#3ZLDUMoU!kAyPF-@>hUGH?$&P=i4=x+2b+T0-LoA|$kl;uM=P z#!Id%_}M~P23@o!;5WSaV#ly1+f2{}bzDSvucAwno4P!tEGQUIf;5*OSO99nBb;() zR*GS=j1PT6GtRve@j*h1&6=?PTrSh9}dm;*Vo3BpzM$gHLgLRNGxAYstfbE2>k@>Y`47K`J(}6%H3JBwPiLk zS1FaC{p-ij%yBWHDQ99#q@p!x#+NcE#n9B&<#~aqLnuVTUog4j=d(@Ari+HI_fCID zH7`P=KVs3}xiG%^z)Vnh)~Sh$5)Tx(@8cPhRP)m3^fa_QXgTc%GN21ytm=&G*4FF* z)Xdh#TvUL1MrE&|nfS5Gn)q*lt|0f9^oTw%x|aq7XjGQ(!vJRx8@^U?tHU!riFEe7 zzQc37x(Tx`k)99;Da%8>FH2v8=EZS>jCpVDQ@+3S%#lm{v5Gntae->14wZ>0Y`@9~ zXK_ll{KKBWbL7zzI`2WI4@Oe{z^a}HrX05T>JTqR>7^NHjPjnuBap`+$1I!x%I%R{ zR`976d%ql$xTyPh7G@4CF%oPG>vdk3UjMnMy^5!T@obJEnf5bCBjuvUa7E7+LjGH) zGsgvK<8>0liG(U*$>=-KL&DN_U6h66G;Td3e%*WEUnA$WH!ILp0uEKU-j zrl1mn&EhWSVdI;zrXT-X$BHN9rM)%#Iy=zv6T2haU_xWC=6bH1{=e<`N3l8CsnX9$ zw8#B_)(wxyE^`6u!HZVOnlq3SuwyT^eK)Z|I!nqw^4$S#Zl=ixw~bHC)Sj%(WJApC zBg9X&b&$AF=bHikAWeGK6pf+jgZajQ>$?H8kY4DD@V^f_L2^c2`Y_`8;Ujlkk#JkZ ze_ED2OTsnXw>YpQ-U6}Cn`dytI(9e&C#W39(+HVDi1Q}t*_bj zEpmJIfg2me+3*(9<>=~r(~-+I9<&}vY|&y*1`ywm4Ke zSfR5ay4RB5H6$G9$rZo1>;xF5{D=+{@LocXlz19~+NKG-cu(Y;H&qOB#X(lQnVHHb zR=J+iy$>aPU|XlcUUQm2!`Cx81s#`32dSOMqmh5aHzXJSTX$goi@AI+BejVZj<5mc z7J!JlF{#LFXeNTkq48YUurXfw;kS>}i$|9QG7wykK~8w9V>w>4>ZrO0>t##p8G=;l zWqjMyzM)m~vc@LeLuT`MeiR>xpb>15YE30vJ0otu$YYfCWdu@+gBO zR2*n@Q13Qr1RR+Zz;EBH_oc&C7&S~d!W;d0J!h{X2*=#`Uv=;Pn*2vpVVq1|YEh-& zi>Rb}tmRP&{RjMo+2O0(DgwpwL8OmkELd^p>)>pi)S!DlUn-{{_r8`<-PaB^L_6&b zDD*s+0b%arSE!m2l0rZqfb0(R@ic4Oa0y7qVx#U9}k6_JtG2^=RB z|NXL^wr_*Mm4!bg-=Ns0()3@O7W(f0Q3VJVKKjyvf|8obgd6ZNOL;ZwDE7BJ78Kw6 zrfaqTtb!U>LLPouEsYcEUX(-BIYA~QdcIumPSK&%oCzQVGY+U&4W7iA?)%KQH(}CTKLMnlncFPtDN>5 zHid9-1!%sWZa;KmqaarpO5v5eBHOO57Gpq@?E%&7Qr(>PzG0b zG#Pv@hU0r(j(;e%>Fm9Qfo<9|h`0VeMPMBN_hWt|P1jl}Sl4{*HX1c0)7reO3@^R| z)@tx59Ytl3i3Mb#lnkJcb-9IBQ_{)k8!ubHe0r03vajZ%G7RGK374fTj@3( z`bYQEdyig4?nzy@y6ZNwrQKkkiQNf|plsF>tMOem;>#MK-%PM?ntCAno5^^Byw*j~ z99DkJhqOg%;&fCIbF2BlO5ieI`qsjGvP|>tKqU54rq1JO=rw>YyI?Aa{%;)+Wk28_ z$9kn5r-LdtyuJ95fUw7`s}$@5*O_JtM~cUjL4V6C)T>0|v4vM~CJ_M))ZTs1=#Jg> zjro~@2oIsp3clk0oZEDe7QfV5bH?W-&E&$CF*6lG?ajj5Wx`btGSls=@Rqf>oOVwu zJt=xb%Jh{F+<5#r4;UJCu+;Ib#l=#vDz@AL|2+?Y`P>A3HcM0i+4Ykrs1=u?s#aH#~TInAkpGf<3 zV8YV~AbcHvRqv217=p&m9F)L{jer9ciBV_bIico^11}(JMqX+P-ZIW*P`%q5@*zqEf`*}_ull&SMXe;hYh}C67~w66{ypZ12P1Ss9)pm7xF%i4QR{s3~i%TDQ$wd z>C>mqp%oYWxRqIz^x?oJ{`t2`0rtK41rxs-N%Au^7*AYQ`}1;zRy1A9!@-kQkC5+b z#M#_Wapo=r+xR>mD}V3iCBhyX*y!o;LLUBQ7c2_QT>#e*HTqKwRdgw6dD+n`-^&Su zyZOp#ewS7ZGlHACU!^t!TFK+R^T{Msn%&bs)a83$v?)Bm`)1^r-T~tgEG-FH5A@Nw zgPLbY9DY{>$TpD+h7X#2ItCW;1b9| z!c=ZWTn`+9Xq{9sn}83!KOj#0r_4uNC0ivd=Y5WWl2DEsGQ2zwd}|h*WeTzkNsc@R zKEcU-UqreB$oVuLu@FvpKk84Wg#h5X%h;vr6Y`)-^@3->o2Vs-DYvwv)yG#50PKi0 zwvE$jLPYtU|JFIRZ9BNf(?GQE-7$D(KH~w7?=s@EjFzb^!!w&&`KW}lv{0nXZT&H z3(L7I;;R@kU0!m%SCV&YUVe|tBL@WC6y%Dxg)TxPz7nR-V-qU8^k%-Tej=1zv6)Uw z+&U!>G$8orAlJcBBT?bn4`x~IAaW+*lGSuGnh;K)mZn2frcR{Y1-e{Bn0CmhQix4| z{k@V&!*1D7^cd;8oSWw_s08EUol{{PKXW=F<8I3cOPp*Oymey03XPKT#aRsvk``6h zM$c-IX1pH+Tsw@g`wtw_3BAm-;?{ul)}vPG&0kr^?SDYxA2YpIY%~^OXXNz7;ZgO( zqq+I@-Ug%YUt4{?tvyz+t?c3QYSWcXwM(T$Q6;ak)FJ6sgyCYO^cO+g;^Q_}llwx4 z*unJ1;lf=B5VU$*>!R6ZUJDwOLJzluXQ<9lAyQq}>A@+Sg09qU6*QrozwD50PfOf5 zgT>{q1SJ@yntq$|g=gqwU%fC6nEHNrNvkH*MK(tPq3}a)^?~Y7Exb5JNH+N$saE9m zcW$;y8|jOp)fFY(!`WNQb{X-dK=dWd${w|!Rox77&P4ZG)_A$bTYV}OJwn9RvRG|{ zZHlL;xJ+z9eX&QnWys>ef!Uf4hFZzj&iNtzLqCxl_Bk{+;8{UR8T6!DiWnF8c|5YK zT7LRZBIssP1LaWa$^9+)%3PXI88jDa&J~fXcKmB8zkuCCo+BB@IfO@K^n-Ad!kCBo zdw9mx1xkK3n1*T_8;?qSZ(3pA8!=Sd^0neXDFsS*!eCd5y$r@L=yW(cJiEcBheZMH zYY7%ThxlLz6xJdp2A&LgxkK^mdkzR<)phx(JP?dwlcaDu6$4N7zJ`Oe~z>dt+8Jgtb$kVJ09&vT#NUILg6>^FNa z0A68}58b;+i^kU?q&>`mL-E$HsYYpywf1y%C9mgEb2Pm%YJf>2%lN6-5WB;-)1Wrj z@R%Qq6cpf)(`R$=7nu4!(H@6|I1_qzzxWXrlvFj^nZ*$2RE~SwjD$Q_y~=VGCyTRi zC3sI%lJGgCEsE|Xfl=lq9=Z_qIYxgho@|48H~JQ#I8;9OyoNorY;6-CL=L0I*F;L==7(j2P!)ZB{~+ywb%43x~Gxx5^T6& zC}w&~ulc?(jki;pyOCioe80I)u~+5 zeN=)GaN*fE{_eb&y$;z4a_B;r@g5_aGuO^v9kwT^WwJ%O*2~_8;TNO}tB_CH??^*~ z3ku=Vo~Ec_I#Jz&_B!s&)gQdn8%7G_757eclUkPN@`wW8unT6C#S*PWE^enV6KXor zm+KSEqe`w-7p%=Do7#dsnj4YvGB0M^f>EmdHk(DMlA^!u06S~kj6oHUZh71w|Jn_S6S`Ux zu>qG6%MrWuUrTYWg4l`^ybOoK9u;_wku4=8rt-ze_u>BRSN-)+3gtyK7h*csCsCOE z8`Wqe4nkUHI7jZN(JrMoz$)BENAJfUfoOdL1~TAJ3@hBHy?uzOckJHyPDsMLoIc3; zfA$Y!6@*!JE*&0FANjtIl>OegpffGrrZ%6e#Obw3Z}L9#P(S8hM`_>>9+k4f&n`;{ zSvc4k=d*xIf`I?{-F$TlwdIya`yMI|nulIxVdD^Yy)U^V#2o`Pu{)tE$9!v5upDFC z>pre`F8AtN<(-lL+gr4Kk`>TP`*(lP>_1=!DEh^658sTU-oPR~XBV{TvDRo7xuLnP zq2hU_z!#pgP3!kp7MYKlEdPCQH8=Kx)Lnrz-RO0R3s$+c(d;_iH)un}o!_O5=Ep7r z<-{Td!*gw}!7%|4BZLqp{@g7_1)Z2;(*znLO z(s1Wwt-6Kpbv(=UAvpX}9Rb-q`R9e~w2q+)#3B;jXHw7@ljL!(uJ?(2vzR<2s5Grj zO;bTK*%R+-Cu$A)!661C1s9jR-`fIc?(+F-IfDzdQ-AGjcT>w zO;Y*)!(pf{GwaUTeP9c~CTc4m=kKC+B_+|okVk?owxQ2Z%h-1F2Y6s7jPSK{FNi`y zy>Wy`KQAVnj-o%MJVuU#mJJv$Ju7_P!y|9uzKhFJfk{U8Nh@^uc0};T=hFU6G|53T z3TLau_+$Mh94b!2zxc6Vh7t@NQdA1x1kDbYnR}`1-h2%^#|oBQ7WffdXeYj9ZO%QC zuaj~Ah0q^Zyn(`6ey-tIyltwF0;tXaWRO7|rhnURY7o8(ICuOwCsUwK7_o#6(?yxv z|IfzE_yrZp;z~gr-#R)Vc&5myog6097wSTv*u@_)vl-{RjxD{R>CGJHf`Xet>ACzL zvouEFUKtDvyh9btSi8slI;$1LtKaC$G-HE3zzdy=elHN6i1bILWy}he~dEHQUS^$tG2K8g>J#R^4_1 zG3-i9toGyZhn6^8E{HzTTL18r^Xn9q-(fYK)$zM zm3~s^>nr&O6;v~A#8%p49$`a;k;V)`;m-5N$UsG$JLC^5DA$Bq!8ja%hWshQP*3G= zt*lJqgk@$3hIoJD4UWV40A;!U7GR%#+xIX-PNn6$_tX zO}0}nMe{0BtH*^`TCIpAGVz|r+~)C`k`*&Np)P1KiWbg$w;||n>9w@yyi_Vr|IgqX zJ7*f^u1p(6Ftt6S@h+5S&Mw$2Z-YmaiHfWw>j$ITDw1VHk3ZA}+kvFy!ke$ycWjjJbObS$(I)4>WB~{8(*6ifCgfDl|;aT^(z%S-9-dFnQI{@66%>gkV$a+8Uk| zaL>O#tD=YV7{#uz5f(a1Ka&46)hKygJP@*x63%uhFSq8azPFfSL?FDsOA1g_TaDpx z1^y9tTH`S7o^3Wg3z98mdLdSE?z_du8H*VyH+QJtNcbzg3ru`Rw{EdDUVms^d20dfBHdIx%Q6cNR3)m)%^C;IvWk?iPNM zRv_#8v~JdNr%m7!H&oyAABur2r);i1+9NI7!%-m8|kp6oWR~ z?OBxr;8Y>$c6iub7Q1_+q|C8ffq{_?$CL9wC3j@dwx6vU+4K~|062EULD18<(;;sf zD`!1S&Q{KJOA9EFN%^-nQ^%NIa3(E=>x^Q@IWC&=pznvTh>X(5!yVO-o+?w7WYo_1 zjhNXq+9;kl8PdF4EI;X2%vU|qV|9qza&47#%jTA;kC)Ot{Ue-l$m-^|jdrJcUm_(K zzQx1C>1SRKck9|8aWlm%-M24jq~3qZw7Ub_Z!2{z}GS7W}-a z(7wZkzcV55#m%Q-KXl!7@6@~RWNN!T3OXp>9@UQL&!ign{=LcHiwb?@5@Hh9=r?ZY z>F}zj9M508Qo4r!oYHn#>43%rUSeqU@Ll}=aAbIi)?2!Wx$;}0skK|qD0*(Nc3?WD z=DI|y^%cE((EqitqfNF5ohABED4(Kepxcq;?of5LJQ(Tg>5F7L9_!Gw^K0C|nb%4< zJ#oqwlnBa}?sfXlche$@>tn_=FW6!CZ{QjhN|S~5X_QUVTx}PNKA$;7myGUozq?Or zir2ZKat_O975=v_D|uD>W`*uC-;F57P3z+B2Di1L3oWY6O}SplZs}%?nR#1!=xbvQ zsG_3KsA(?POpw$m38$(%Osk|`V<~qFH{#OGlE0oF8~z$PV~RnE31y9LBVA{$4++_e z;58#=_>RL^k~3G(KERnh(Cd0kAr)_$i>~FX9H0MpsETAOB;Jjexji=mPA#glW=G#% zB#(XhWXj}Cl~yNf18vW!*ZrVS9ok~4q7QzKwTu2m?q*v%=Le1+;plh4Pv(YieExNzYwRl%*zBgLs=KPv~i6C;m}ohYk3MO4aIyz##b zTT*q-voms++T^DSrY;}ub&lfjogK+D-6|$}P67*+rK{g%|D(0vp!5trgCykdG(9QP zdX65|I8$;}JvrR-}HTrjazib~BFmo=g|2J0MAqQWyW@xqP&nNzl_2!=ri zb~KxV#sw=%yus_Fw0qG)>q8~YxL-^`lwK?BO=Oo7kBq7y1+FXQB2>C@)EbD0ZE8p5 zo!ZHiz)w;n)Xtt#t|X9gJnJh&`z9~R7T)gQkjpF6Ddp{td%L6)vV+wvC3#^G&jqWb zbJ}FnF8>=$r=wI&i{7%}#VF3BGVL8dfzK1}Z*koWOLbP_DnVY5{Ns+X;`;k1WJ@}U zWcJ}BG+jfJ$qqPHf_4B)KRm%N{^4e2U!}}_1f=+==@&Cx}UL16JcOxiC6%A+I8|zKi{J7`` z5$5!vGGFgq1p1)y$TrsDC>Fe^XJPzQ2bJ}d9#O|QV237I+W@(j^uTe$i2?wulhDw8UZ_l;QED)(7$ufqbJy^1tx)C}R240z zUvgoFO1QSui{q4++NM@Q0U!!T=DG>Wk0F}HSahzTq;oBQ>Yd`IoIHto4bi>vB>^p^ znP_z=XsVg)OXB~-_jh82-*DHUB7T@T8b8jYH9=xCAAC8e2FDKxS^~*OS&dJ$Zh6Ej z8UUTY_U4EwB|c*x_ikm;Dx)#6Dl;2mws6Bi-*M!>bw3Y=lCp)!SxT=UfNQc)@ONW4 z%P;m#hx!%D5o-wm;={T?oY9-9lzA9mxZ`?bu zce53k_qh09toN4+!*(<{+DKnje}avs_E0^-M~Hh2uW>^~Lo*p@VNSY@-PwgjBq7xO z#iVOLgZ%W$Ku}_y#bjZg{0=eg?~(7z=O>6Ix<9{;M<;ura=KV%*zhphfH38Otkc!s zDeOhe4{%fvFe(YKxY&nwUV6MKZNfU%xl*)5krwY%pS8_oN>cYL=TnE$t%*;pMC3j!Q4x|TGakY+uuK9Tw|din=K_dcvjmfHc6?G z3Mb9(``h!NoQ0ys>^xT>>8gyHG$Thap4z5PUf#<2O&Dac?C;j z^_1_i4yh8Yjk^9HOV=LH^#1>yPM2@#a=M_1ouU*W!cNG#NhL{a?ycO7S-A|k>~u;O zLI@$0J2P^bVcLoibID~cn^`WKa+^zbX_tQQ9*^IDHJ|JI^M1eHuiNwa4Ad^`&$s{! z$u))5T`J*>ld<)~^*wW#lUy>g$Sx2L-@QV2+V$$O`XX zi@R5k_K+QfcvYt*`Hio%aSD;U{*C(6Yij;LV4!Sp+eK#B6(T%6A+l8lseT+*^SsXt zcFIx<51y`mAB!Zbz`ykW31 zdBDoZ0-#+0l+ij#taWAVNdHt0Y&O4^5E69Vf5HrhJ$lgOB_u)ym+c>Ja#OraJnC<| zSL-qvD_x))E$2QT4T&sO5jylBkN{F?vQil$o{tC_I#x<;BMR)L&Rnk@K@g$k`m=@U zmo|IKC0)!gdprLOlUuC^w}bo&pl2L%aCV~SaGD|z)0odIzqKTM(2lhOi|PI9WTjM+ zpdb|f8!ksTgPsgl@*b)vesIdXbBy8zcb+%1jt(3#L0!>0Y~dTfX1o9p))4`@O7Bxd z7WFFJ@r1)t#>lYY`|GQm$8T&|wss*_{r(o`f`XFrUd{(BhD4-2e}O+0&CUjUZ`mQz z;PAAX^M`B-f;rH@TgXn+*C{0II|mQDOf_;%vZjwI>zf!XjaSgt9JUNCY8Tt1R2V5t zq(=4F_{D*Q9-@jr{3t2qa*B4wn6{Rbmx-lsHFSgLsLnidgihEq=c|W7bwPGtInGCC}^-?5>e9jcx>%Sl5V^*fVYJot4Nvx4{QBK$F^Q-TKuXw&o8VE~d zb~mz#{^x}|p+OsQCu*P*4~5jPMn$2MZswEwq|c_%)Kivv6J#p*8@8t_jzya)(HPhmd7*C zzK1?ptg9C}=n}}mpfO{t0&RsLd8b34Ypa&663~wAYx1S*_Wq@XaJT;YVaNm%7(1KI zOtz)$UtJxRi`26gBl5rR=wvzJ9{R?j^m2{gw!^Uw9)Tj~Y*l*4X#X~hgKXW(DA;ZTyxSI?nBvd%#PjN3DsDwMaMA`h{|enRbDCh;`C!x&bE~# za`lX;O;l_}2f^y@ge} zdtrjx=U4ya@yOZ4!x_ihQHbxc$#mcs#RsyOBzP6kwKbrhd2yi#OHF^y*1_)eB?Cd}w^_+mD)eI^DM8g)V&a8T8w7!Vka3 zt?7=cF>rK6LzVR}xkrI3q(AS9ok(bqe+v%Ba;@_%v2egTzC3KRrQ2rs&fXV;>+x19 zM-w?RzZiIQp3&`F-fJ$Ge|%j?0%9Fq_+N6PBNfocoF348_j? zUTXg>#IC)6_D&BSseU#Uv31WDx8LCQ_XnCyHBQe?o4ymq;F+&?K z6T@e<{ug`Ja0|rm_{oUjTk^m`@}k^9sI&%`8~o#KC*=~%D{O|}gy&>i`GnWl?EMs* zhU|8|A@M-_!e)oS6*8y>EKo6J@aPl=QV$noOh2V|g4^A-e>;+b}{%v{TS({Cx64 zxWU}!Nyf-RP*b`HTRiMcf860Z$l>-*=4-Fk7U)D?j8VDFdd*PBg#``%l6%*(sCJ3> zn@M>Nb>Zhsq?%R!xGST#zjLn^IgnXRSyvu@tL|D++zYok4nW_5pf!7b<=b(UV~W4z z3_x}HX6M@i^kFtAyZHek*|M|dXk;pTm!N2Q8pkrc~m!suE)-un0NSa5>Z>~YG=5ZnZI9yQq zVi^b$STpc~QE;WcR~1n(jK9g%?cLRSKS|c$s121_s^`a$vU7YIN&If)i*|mAohLa% zn5jjtjLUUytlgd<$mkN4OEa?x$JPGW`PPRjJ6E6ZOD=FdhV4v>T{R>dfvg0}pM7Up zT9=)-5Jz1QA$6Qd%ZuqzttEJUnd-|R`CQ9~ty7oxuN67M#KXW0exkF5SN~4seOLZX zgd*=;$q{8Cx#AVXgQ^K?#? z?eR@}v1_LvnzU3knojxeNo&2zP;{aWU?;puPZC}V$VdW7<`{lk$!GHjh)Ks(e5jXZ zi-`wXwph}Gm|iieKRK~wkQF14L=vNS?RpZjt|NN_(11&02#;lHA?lNhreu@v%+3hN zKOI$mU4*XiVJqC(vslUv*+RR5{pU}mx%nol}ccKjkvpHkbDC~jH)~P?_UIB zNCzMEsn6~Y-EoNIGg*ELl2-remz>d#(6<1vdSFk1u(^bVysDdoiB)ry30P&Y+S~1B zO{c+&u7#i{+e78;hmc5YW zB#CMEY{sOl@HzEIS0HX>4!%rn_4e$0Ks02o>Cud$4@q;gaX?TRw%{k_7Q8q;6SV?~ z1!gCn+H$|b1vgJLYF1jVrhwhAvXMd6%Ryd>eiS%=-Cv(a6hzuYA)nwEX>OgiIGmZTu7 zTU`tqMAC#e#!qBrLB&vrG$DE~-(EIl%;WotwL(Vo1UckCqLo) zEGu>Gbr~YzMjWZaxJ;baFS$QIgH4t3GyYWNuyhW$V#JI0*& zX>d<757~jd4+FTqu1Qi92@J_;oHueKG_r@f4!~WbBQ?@=2skNCZ|rv8&%)mc$B4rY zW=U#I(yXWh;h$Z{3xM`usulq4s+PhgGoqC8(ygds2~}bp2^$4~lH4mITmCWFY*vhY z(8bd;;T3r`)Q2+%ZNjO1Iw)y*l@>~0N;F1~2ZvCXjj960JE*^3jr+Ko1m4^pJnX^b zoe^pZ(1pCo$EU64!5sd#$RU+~VR`&DQ05%R5m$90+58a5S{qEuycP5RquTk`tWRG} zOh?SY7k7-V&~fuA_O`MP6T`?4!?U9ff%I6g9)79@e7%)i!nrQiK#n_~c$kw1y&~TC zZO=ha>F5Ck?=B>$)c=xud<4{SzCm@_{M&Bqp9;}B{BS^gSVy@S^Kuc~rN=I&?f%7Q z4=Sw5;+{Q2^5VVU#cR^~UvdI2<+a!_CQrDoIp*<0>RWdqCr`gqtjMh7=^;b=1o`=p z(f5ZC>YwzQf5{CV0kIPPdtXg49n6nXmk@y06VOirZ9tlM-zV}))e=kkt^731J;a^8 zV)_hB#%um_p+v|cj%^?P+6S;(P)gZn0l{_y4*@Rl&F(DuL!)_KYnYLs#X!r z@@|4h0m5Er(Lf{A{3sZaLn{}f5^jE^eg%hp8h|c%Os&V>m~gUM!}THLNitCt$t+za zz8L|7vJG8zqt3Fclj5-)wT>_;7T6mUIi{Urn0(-tm8Q3d;_w{_SeAbDm--6Dixypt z%MKF#qy+GVp)&rMZ-X>J;#IqK-*zT$wq|4^7g_i?NherV6Cc~xcO2$URjuZlqRG_9 z@Zu}t{lX<OLx;(9~lAS>o$nR&$fF)5aT)i|N(JB);C%Px~3`^sC~|CEIYH&*a!R}Vs(COiCj)MO)d zS;|f7rvJ;X}>41 zi$RT{?}K^i`(bjG?Kqzp`YDdZQlW&3eGrbaG(Yg+lr1D-gX&g2laG za@Q9xvNuL~cax*eluD>S=GK3fNb?|P_X2B7h=W>_sjU3Tu9%z9k1(YQYV$HbpYTiW z7U5dz*Q)0p-zUYOzy(&VGu07R+uzs%m2A!s8=s-x)st*4d41ZZGt+#hu+kiIcF1^9 zrV<854V5R+qAF;6esg{T`2j4W#5$%?H%}#WD`FWLXM(BJCT*E;fRk85RX{gS9x3L z!yjDN=yb3q?;rU+#uqv!b1t1$GVUegnu&T6b&|jQ=?8Rbd=SvqMq@U8M}Mq+B9rKx zo!B~%eb4wWsI>a3?!l57vM*`d^Q(|FDzA!PUcs>b^!$Gb_2o-d!;NNJ3iN-;y$G#^ zN+ZEGy%+8&jLZ);ftS#v^MHV9%D2&ShS;8WkN@c0-Y7PdRg`2&_GNoo`c@4eH&+qj zWDgY4Qr-{y-=D2HZ%33_2V^uIyk{V=SfA*w4_Bk>$nil>S4a~w+cz@mCBtn)SZ(X9n^n zS;*3!KK7rGVSa`>7yXjk=Foz=goc$2Gu=cem&DD1WuUCs(fg>frnmi2?7? zA?(;bwqU*dILsTe)sRWov=OS{R_uc=pQ$m|aZ$xL?|M0O)1`0!O?NFKzW`i)AEFZq z6EM-hiEBM2ykj?$GMOr_ShUo5$W)(tie`6Z9Isn)4jS!Ihh{*!fn^jM+l=8_?I7zU zh=6H-6I?>g(^Dz<6B!p1)U_oMl4zuqH5AUT#D0Up{1h5W&%&YvC8_q5+HL3h8pu9|5>pq$95NvH8vZPW{Mmh%Wn*S#l}~?U-=O%5%SW*T}$NOqYpg+y{TXc~Y0N z3g3l9{3Yj5Y0Pe-HaVZx*j@D}r&H%v@8k6x#!YY|GJ=wb8S7oTxH>~u55-K1^;U3fIKpP^F$a)x79tlGpMawZQoJHj(S5n< z)hzid2^CsL5@vi3$>YdK3%!Ne(x?xplM7xK>R~lw7w^X0X>nz zvc|!s`gS+ES?z*7%5Eu&7kXe#A2b>Gp}dL7sgcxf!mSl3a367vce8O{6)s`Mc<|P! z?9{Lc#?Yeq$HhC6j^{4zh?VQ@3@C1gT@y)L`zTa*PH@_M)BOD2OX-toGCl`Y$d+3l zpZxIy!{^t}p-wHR4MVykHfAefCK#}|qH3i6tlwT#(?})QGUJC&V3aQoc2n2sP~du4 zHw#Zq$tU!wrXJ;G)9ghSR(19 z7@$$P1h$V@mGaB+lwJ-z1`dB#7WDb_q@*K7`n5z}P})E;rPyR%9jU7Nz#N?%<7>YM z^><&8f!LRbSHZ_?r=zL5-vENWj`}icWhp{yH2r}bqx<*@DP84%#zyxaG_=`9Ci{4^Fefs31XYce_Nb;=|>i?oF zsd{(7idW>s0zRay5ca0^Ocj`CBlu8J=|wc%4<%}|wa|~CUDAKo-U&ZtQ@s@%55r-e zjNj8uTw{N#+WAc}=6KT+tAxtKvBP@JeX@0|KvAaQc}}6_EJ!ER`$!kb{=LL_x0tDw z2Z`-;QdCbs1v6W=vB$0YUUIy^Bx&Sr^YTwW#@#fp!Ah(-*9)Du00^jlZeV}Cm4Wwr z7C8x1(_~ph{=5$poQ_CTO-TG9kRd32PTf+ zoS4F-F#tqQwt*OX->|$DUdDXVK9nyVdCL|ezjpt0b=WT@3~) zBQzpudtzVZdyL16X6dVtGyYC-_RG@8Pl^|rCr~o~Q@C2<2-?FxujYLrbhR?G=;OT& zdYu~RYAQ=qROLuosTSRI3ZM%>w1dn5UBJlY*BWTeSNw8nYd!EtrciEb-L`EJ>K~c> zI}M%~VTv^sv)r90!InZ7`pPAxA^z`6WD#9d2|QXA5>K-JSnpded-kLj|=hdc=!(Z~0k*yB z@XAO+<~b&%P(hB-DMuaif!07&BLVY-vS~;XT|x8J zJzN{_VMscKHz<*=+5cew@t)GD7M8BJRLRbIZ`aa9FMd*7r>|6lY-Yk;LPKm@#F9a^ zJFi>P541djDniC=ZcIeI555XEeJn`)q}YsUA`=x~pt3Fm{*ptBewQeSgE5-U5$O04 z2Qk$^2i>#c%&>x-=6U3OQi2mCWC-9g zEw4ev@!wDEtMfTdB{aDSxQ_;uO67dT5$iL$PmCUZxGVh2xT3;r z=%ohcgBx|(H#`+&iY2WA6`od{Ehi zUE@VhpBT0@v|PVProbU>7HwVrou!+!)y!>gc9dEk4%*BUbKh}4B|TU}1DvOiWDD23 zJYMs~i0n(!7m#Ecs-EkYyeW}vem5fZ*qerO?`a@SOvNWJ^d=K8PqPFO#m2-9Km`W0 zr+{AJ>=Qj}b_beUho62{Jyj|jeJD)>3Wl$nKBL06-_#A?dIN3nXXd!6p>i=!i58tR_2kBbbGH? zptG!d=bkgWLwz*@o-p!wQS`%e!#xdK80=P8O~y863CzgAs)hM)P+jn@G1WoT@M1$@ z0SCjgE1>5ixaS&U1UvdeC^zGra z=ykKnPW1s$X#pbLXW5I|_W1IP9lUkfkt!|pRhtYwpewZQ>UJLS3>Qw5tsmqBof=>| zC*U|WQr=XNjA6m7?guXJ{pM=o71GzsY?i2u%}A}-_VCf>c9JcnC;@jo^$E4$R~ zo)XOD)V9^rM$hc4cn5$i;MI(&PQYf4#1+i~MOG z!$*>3mH_|xno&6CVgPV|WwY8Z)-l4X1#Zl3_Q>VbOO@r@bRul{FQ3QA=zy|iSd$4_ z&a)El&Lq#xPnGUNcM+{1&kI)5)kzpJ^?q}P`26L;a8n>97>$P&OQg-^jEbg z%s|RWYYqjmNvTYgJ_BLgtT=6``&M1EyN48daPo7XH^?l^Ur(MguoNgzc(h+~Z~7rg zI?&^zgrp3vY%zS6|IV$57DYF`W#)gNm*X{F7yRTzk~ijQy0xO&OAt;w%GCXqNw4-s z?jqkh-1L|m=zF?+0zTV0q?RP*kz!!NmLK(w?dJM0&&%EFBTBi!NN zf+Io|ws4&NQQ6@Wc*}pJ)9jHcL}IOWs@AD!UV71!Deou7vuoZ68J}L23nR*#oAm)k zPCfpkfXp>>Z*doGHBMJ;<;P9Q&3=vVC(6sIp{dxp#$9bY_WUzswh-sAw7^0d)>k0BBn zl{=B0E$;5I{6~~j=`iK<1Z37vGQ>fuy`LyHDpoirj2vXL(gU3qyGxcN2IW?pS@jP;$W%R*&4W=V7!SEb% zQT_crZG&_X1x>Je9cKO&sptnerkp^MN}aP{d;Auq`JVKO}+M5MJZB!K*ME0ms~HMTkH+(7#>diO;<+4tU$&Y%u6E6#Jy|#)v$6~u z@v=^6Oha;+HczHDS8sQc(KG2TOXMX6*_W%(SECGSRM9wIc{0ZQ);2)R5EbdOq7HY0 z!|Iou4#Wrq{?2_-`?Ww}c| zjo3wGI-z65}CJJ8p3?+n!pRfwWuDS8ZQx|^!-3t~F@B5n$>K2Ft z-cG@{Q+(anp@6X-0PWzxfBbM@6vBHy4Dsq=x3yx)E+P2+WzEA_ALbeU@NU*zvTU&RvB}6|oZ3`&R`}9jr7lja(P5p0d?Vv6> zOxy4pby?XfcYzd3an*qY00Ob*>yUWmmNct)Piyu9P6=qbT0z>ZZ+(qQf3diuPJCla z9bu|^PRpx7mC=loDI)SKp7N6cFVaY;Thi1KrokK171)!Y$If!=j!S<+ClvHv!|U!Vjf6L zmR9IrceA@IQ#1F;e0KJBp{i) z;SIP{X`mm)hm64RU#e6$WlM|pBvDt1awx+NNZa|(PX7S$OMjiJ`~?S42@#(^GRt{W z;L;5|?+w6@NYaN#7^O2Fx$NVB2^YjZ+w=O%=90|1)niUi?)UnCGrxK89%!ZrW9}_u zlB799f4mvo+2-rCJL5pPRfI|q;PK&?Bbv7{FT+6?fO;cu+gWFP6>lflUZo90X^T{c z0$lzE1)E=T_2)(gxj-oKp68C$)Ze(xhRJtu7in=h6=hv93SpHYzH6wGZfvAR1nt-% z?w!iym(o@KMi(sZ{^3Z^MsIqkyI26m0*L20cIbjq#vZqeRj6ZS1z8go0e>S(3IZx|tVYsZ!Bjv^mFzFiNZOVk@ z?Y$){r)+0k@N3E|66>@3hPy8tXrSx*-Yv4k!(yt|a9rocxKRtxdHKC`j3E1(pkNHh z!_FS~C3h!66?dOpzgQqPw}{FFy)4ejL{iGz-NteErD@s!5lF(AbvaL?=dwUV=)QGQ zLjrE(Fi0H@6Aus$9b9CQxo<(=yCq~{$ywgOli0|T)#&s{48JX66qIHyP{Y!eRYz!# zO#*u8YrvRn@$vy3)g}G+#$ao?sl~2%)e_C-<82E`2=pZQZHKn2izS(BBTfJJl(V(P z`Kd!xDVJ$2zVvqgN74jaZ^Z~zH#|CZ8K4#Y2oZircce_gIs0}ka2q>~@+e4CAYp8uiv3i>* zZ_Lh^D+ZALXU+HWFXgQ)!`>5P&_p-N(eN16nk(4&Rq)a*RN{?htBl;Ebakw4p_@U{ zlyk*|EZg2$p|=v~Jj)d>er<5N%3hQ~(vh;RRGHGq!@^K@kOb7A z;a#1xNx^TB2T;#lRSz#x(4|b}Y-qfZ&C8>CL4exSCcUv#b|(Cc(;IOlkRZlax9wP& z{#ZX(DadxfNY>|ug5H7ii;~(#7M|m3D`kR-u^YG+uL!};94w46R^QkTZr*+=bO?UH zC2%;6vJPmOsJ%x+(uuquY zs^7r8HXevcZ^#q6Ozf8F+&QepjB%ohmBS=Dn5}h$TF3f`Ff?MVyzz4L^|5BxIic}D zWz4)iZaEv&#TTecBfFt(dh!^1KZTG<2N=U@UoWJ~e`9=HFcZW|S+ZRr<1w9s;&noTfKa%~U*gC=fD;F;HTFeBzjgkG9UBR0sf$m$Tu@a&-Mga=y~E2< zHUSEhJNw9I8^IKqvg-Zsh<7pRY1PoXlX#NYs0-IJ)L(zqc}2;Gg^+2f3yTT@@9>2r zs7(gJR_WOQ^chiMQU{7-8|}+I`raG);}U}%85*1{vG1?xSX>t2S|x^^6fNJmySnbl z4omeM#*jSA)0z^i^1J%HuP`1FN#b4=~+B}}u(&;er(R{z?%HUL59*04=5Wb~VX~%<-ate<})Q*kYv62c} zBc?(9S+%69UFXPsmwFyQgM-)k3fXaGmm~uCc+Z$wNiv11$6WX?IZKeTA#>~5(rxi+ zG%g5Y{JV+bS_?*r$ZO8$#B_x#1$)@sSaI*G) zt370j+{C_zN;E(%FS$KH`XyJ6CSIZZ_1#+S;#v);WzbgpK@j-lvX^_{QmQmBJ*}%6 zO*!d12czSN0zdY0gQ54e2wh@^=0~YsDLE$wnH{WSMA`kV`}yJbjX)x(zCS1cL^{LZ zrKp9v5t%+-8Sk1gq=__APk>1Q_Y@X+{)kogst z3$~x{!-b7+JIP0p0<41ub?c(W0p$YCWl6uzMfSGaZliQ32P~bXG=W!Y#U-08M+b=3Fz+u!UGJx7?ENJ-qqSBnv^3M|lNRjk2kuHDCYE%s zL=w|RmTiKEC?4lURbpYMwrL>gu zJZ|dSmC}pT+*X~CFy+Tz6Wy3$-E5;E!n30ent^OSYG!0p{X+C;MX@M8jsqqPZw$}q9zi3Q05HP=p5fe&0LytJE?}v6Q+yu;gnI3<6@`y zCh&ujblvq}ido(wkT`erX1oprPYU0n&%QE^kAGrs@cFs9;1&CR-H9l_@Ift0Z7m=P zz&;Z3a)jA1N_JSsXGO1&0=&W$%Qz;-ubXw$SWflScbgAX{njwzQ2rS*A1kYP$P1Jy zlhocIbf(4BPohc(#H(>vQ6Bc)4MEZ^0xszDMD37rMO#s9zD@pqGih!%zxhnw+NS_V=?nMY;}Fp>dtY%#z1co#mAbKmou7H{;NBzVdOA7k%?(3inUGTtGu)` z%di9JTYKRh@2^X!H_r+%nwfc%&IFCtp4H3a)HYd<&9*dGF9(d+uv15HY9GYtkHecD zot)-iCY^JQm}FtrtNKZ|d$I5`v-f4I(R1krdd=g-oD%382Gz*46B}4(M8@CV!K7f` z+v~d5r34E|cE)5ifR#5w`697yPD;Pz&KD&r+I?o!Z4WsUp$eQbJR~5B+IAT)h_T5K z)9g+hw&08*9z-2+QVL{G^?kn~@@qWTA=yl*3v8X)l9Zl#(A&uUoEvrF%e7adBixT$ zq;o;j+-)j>ysR9~qSv^|K)Iwr%m#D^H5X6@9zK$7B}mHnB1jn(yG+6#L*Yr9&v~G^ zWJsa=VnyCb@zC9}|Dbm1(4@P%6?K%$seyk0ox+W24m6+M_Oh^}`!+Id{Bb%UfBW99 z!u-lK4|o58UWiZnb5Z*oCPT$|8;-4gvmQQo>G|h>PV}7pthg^Vr{MR7fAL*=^PR9f za(#sn^$fQ5M)lfYp!wPj)6em=ORT}5Asv6nMFrdfwJ88b6J%xc&%C+)ySKdBth=~g z|8rv)urW1XhO5gfw*e0&8hs%U#9owA@d?x`NMxwPG1uNz+YG=B%Sg1c_nvP|68K*s z*w!x}r{1x+1OvImNVI-ryK{S-Ne*??FzUl`7OH8!CkWh-_y|qs4HTs_ATF`h^ z#gSpQ<-2sQY9?pyuPVTXSIgfAK-9ZvSL^jTPgSxp96NVW+%;;WZ310sjOBz)W4Huz z3Es69+iZHsLhPW6wRJp+3nbznCi%4d4ohasTj41J-fZ56bTl0j3KgwV?a8Szei^&8_Gf4kF& z=QSSgmD*PVu*rR5BOkG5@3lq-x%`BKe(XV=UR&%C7{k`Q3~@IdFHKkX<^%QN%Z%__ zd;PU-Z*w^(`HQE)Rs3o$IsLPvoEhfLEvDZNKM9SvbcNN1@ zmVh7wwz#-f1*CJ@0N&Qk?G#ZW`eW+H}0wbVlb0l1!BX` z!Xp&8CB4(L0M?S$GHw^wCRhD&^|Q}4fO@=LsRiIIO< z`CRo41yIqr+yI~DB6;x7KbAoe3Nt!$1<#zE=SfaL6N|SO*2>9*=V;tL15$;Gk_<+nQ zyCW*Pfqe&r%EjBu|Jhy_ooj*qH&mweKduUADHPTwD4q4+0|O{@7Jnuk0kGbBW1fBI zyB&n3Cmx^49*qTV6}qH;f2c~?qBnfxG0K7zof8Jn+-(@$Y3e6)^uA?WH32ZASKsA6 z0s)v;dQxpp!`Pa#oFe3XQd-$c<;1^3@$zN8K$s0dO3{Cvlo?F){e$AxrNEm_vZJ(O-~P|KiwgAE9&DoMTs6z|%>;@B2HcY5{Dy4v^M@CK6o5T- z3~FGIseY_M220Nn>ss9U^Y`Myuu3;5)LyFhyOy|Qa;XAOlKp8*cufd=>Ip}P(wwVs z-hGW%$tI*_t(qmg{F|o2>oXu64|PX(6K{JGUYCEKJcI*Md~4nW%cAkmdu)u)bZ|qF zY3cPkQF@v^`dE9Fn4dMZ@cLy|d)u+CY$>J5>zwIAm_yiNo2&0jre&1 z>TxjNuE#a#sP@|+To}L~@US9^S7v2QZNGI9Xv_X#S2>xBG`q4gfw*syk z{+xG!$*w-?!gsQm9;3SRNb-~9J->S=oSWZ~jen%WfuNF|zx@4P?b;Tabguef z%Jj|{?=p{M*$pK34dsqv`#-(EnY4Z4lA#{pP9LuI!W3Dc8o~%M|y4`~vQN zZUuJMkf*G2ZNdx&g0b}%9^+gGEI;=Ixax@TwL9X$x=Gp!HS0!y=0X`o%W^w={e z+(eO|`uq#x;f}@CFa1jg9}s;tFgZ%D66*aNuH~FLD(SKKUt3O2#o6B*%CXd-z;;V9 zQRRwKTIY7!1xxY^a}4ihgu2H;1=I_*+H>m0Znz)H!G_lqXxe&$>KlgU&ZS#PxD`9F z^iM)UsVj`FI_PJOA{Xggy3xZ~aXcWm-lb6myC3`fM=QuFeX)Ie5cn-Ewj}$wdf_*y zHtv3Hy3#0Bw_A^PQ)KD{Okif|hN)J}A_-s~G6H%Axkz#&-n0{TYBo4fT*o`{nI@5g z_MBDDwQkAw()0Zz zJl!Td0+>LaURR~lj6|!KQlWiopy;>V)WDNT=8g~jQP|&Gw80#UtG#gHX!|DM1$;Hi zfIbBz@*6|#1Wqp4IS>C7yvRGcLY&QUqn%yyHO$yu*+V_F?Uo+ZACKx%ZU2@sh@5+@LB=IZOCW_|1OG&9Xaz$ZmTCHz&PlKa~ ze}*&0Qty*- zc;hBLMGl}ZNKr|@f81?Th#CgaPK5O|z4d?Ov-*h)z&(IXMSZ1K^nLT4H1^V>jWnzL zR(Q>(%-8z@fS_qfmx?g`!J4u|di|=Kegv`ylr0c$^wfKA#@tNEqW-I0Y?H3_eeB&j zg_+mN6q+AU5Gjfb_9BjayOanUhof7Q zvcI}ggRI1l5HcV?!bjnwc17rn=G**MsPAq@-7`!;c{iRD=q&=OthNzbbWZiUe6^k`xWXrmhZ!tcFlb<1*HJgjrWooY zyZ6Q@|9#LC%nNNGTv6B{ z^eJan@vaRt;jmikh?SAY>W?(j<0i9%It-*dp07FjG37mR^dGdc8U3)y!`~TPdoTLtgq;iTV z*CJGkI^~w!ZEnda_pz;%EsS+JDTHuFESKDEM%V?zDn-naLfOnBQ^~e$Wp;M?{@(rm z?D1H$efIgh-mlm5^}KX3%?dkFSe=ERjgE%bJuwab-qStyZVN2c@;rQui8Z($*Lmw% z1!_K$N8^Xj)_DG#x3BPN3elya#|0$8(QYK&QH#V<==>I+@O!)UC!aheR6Na**h?EL zzCVoB)eQ64N8GC%hZeU;ffe9DY&pdK*3WyPk$6>j@qC@tt)Eb2hc=cC=X#Yb@*swn3_E%_ z?Nqwh221IpcXm5h52$a;;_9RL5E@*CXKK(2& zzGb?hrkyVH$?FLtmm9SeSQSi69|#o*qB)T0_f6V*hUCm%I0p|9+Dg}*6ZVdN->2SC z(TAwX0Aft(Y7sEKr)xCN5U^R^cQ#8^K@1HWS6vXy=8hb?68bS%$;X&*evle@YsdCNXHPhSz|( zdfRMe{H?~}SjMyrrZyPd9Gq-1Fx@!e(bMUg#^6R1iH*PY52(}RK5E-czp6YHDNSt4HSn%$7zmSuU#TQ#l%QRr0H+!?dA$(xD+ah_Viq zm5{RYrPgU8%#@Yg$q@CB-J4r+9oh=O(Afvfwj+ztri zeZ30Y+}i!Y6KpgtxtV%-n8$@xwy*!BBwUR`6;zl=3CVXO!;o6>>J!Uwo@lJ%J1+jp z_xF;kDsB|{xyyhV*fiJX=imJ`+NJ#Stf3S>%L)s=%ZUb)9>rd@)gmSxssjJG3H3N{ zCwK^R-@ZShj0G9~{eZsbCyR@LNRFkGhyYot>mcx!4(6vLMNmUK{wGVGz&|)Q5j>Bs zHk(gB4&N0|2aROx*&HBXa8T*!-dk$(^oo+DOKh)BgESVjAGspcxc;Ge?#=YQ*9$y9 zjD<0#tDNrb{xk5CPeEtJK?FcHPcP7^sY)x|5BcqY_^%7_F4ddOy(bM=n!I$DFcu|Ct*$`x$)KIB2K4{%{nS zaWR7GD{=-{JY-cr#H~$wi}8DJl$0;@M|0)4Z55i7XpEjeaHS`nuRa7B42eG!zKs27 zd;VEuQudNrU>JRuqjZ{c2D}b+)Vl5y_|fNRF5Jz$6%DgXC+bDM!#c+r0B;7=nr{%s zM~67pl0(3y>feSLXnwPM(7})J=z594zGd+3axZmWO2U3`vxRPVu=^$8Dx8Hj5J#OR zW$^%T0>N!;*be&#Pxe4!=Pxq1Hss9~HFrlF8*rl@r|*Y7lr7s}(eT9k4WvSee<=T> zg>K~Ju2hWIxZTHlK;{s}K$Y^gQk)TI&N76`g*m)Aa6Sm}t^mGi0^ecBGXT~6PNvv? z+zvhonY_GG*3iH3m$Q_X#-1IA;Qtgfb_{Hx{Wm)7x(Din1MdfJ7QFFvPe>`LdR{xB zv~#n~+j|AFDv!MxM^69pQQq`8*F*3N^eVJ3N>LD1EXb67vln~g{TdH`)yLZ)|1Tgt zNY?H(MQ<(QconAG|1k^_EjM&K^Y0&&;hj*m@oBBi8(1{?`0BwC7p`~ku42<;*pwz_ zDRf_GA}`6_cc(+B2t)Ke{JJ)oT@3;=W(pHqH^A4ue8t!tngEb3o-H)~${So53%aL} z33~z;LKt3DVu)#q*awJcAjQb$>Vu#E zB%gEqdCURmwZcXIhWYQ&`f(v%2OYy0eb7stw+A;K+_Horb>)-7@Opsdto|EkwO}KCPBcw{mE;{lq^%^Xv#(d=(ayg_&`qAnc*r}ZSK40B%{cdpS z;An~8e!FHaQHoD|mo>jFxifE5kc(>d6DMw!$BALO(?<^|Mg6)3Qn)t@P@i!5VW|Y_ zIE*;I-ob_vw{=)O+7OIeajKt3AFI}`Dwcn!Q#5VEDBjv=BRi=#Q=gMM{^kq`3>HWE zHF58iWpp&6amSel2VQf@z1I@T)G2EB(qG$yHQWF!-1r116VB`NrMyVc&-k9&-E5hr#`F-PG6v$sKeo00>R;^v1aR_bsCpp z;WF_lbwgq5jzWRfp}t*1PFZ-m5P-kam6i@bz0&nnoVT1FlJi*q!~J(P4+&4uQzVeh z1VbS}?z;nX6Dkr59K4+AW(A`}E8t0~@#lw{z0Ew4t-7`S+FiUwC0k9~@8pXNK*Fz< zANO-ylK|*Lxnl)~avbGm0oYjayBvnVC-Avu|G`QH!RbzEZLTKc&oW-08|`;WWM2sO_FR4$i26O~gB> zYtBm8AYDjuc%2=yXL7Pv#I0Q4@?XJuo-hGIwDCvbWPpwgOI{L_+dZZz>rLSG4uF#be zgr;YBEFPFUlDwCz=$LwNPSAXGe>ds~^jSI+0Q4@!Nk@a+ILmP4C+Ok9W~v*BGwHeTOn!PqCocU;6Krh)(S3LuP*cBCq3Ab0!fGHN0Yv*$ZQZWynckf)J6-a63UB6au*AJKHgV0Gr zzw`1o#P5LY))0S~_T>ww7t}F_N(LQUVPMHu?MNte={sVfuvN2mL!0T!0zvE`b-DLa zqY<3rl?$)lr&lb3|0MpgaOzS(?E9f9o+Y>oMW$+Gnz%F- zYIE?W{ZXVW&Ryes5UsYWh6r3pG)tQ-1K`KoG5FvT#$C!Wp1YQz)>*(prX%m0-R=w( z!QsPBY&pe>eQWs5MXo>So^00~aIY#cKAA`1qTw8Wi$|B+7IUH^q{Z{l#>lSpJ0(5} z4kVCYa~Jvt^$(Dk4awi~ zX1zhLyQ^`B{I$joByPj-=%O5OW5=GR#$IvLt~LNm&*-n7d9F#&LM=E~f+1J1SEaj+ zW+TG6aG*Er6~qO9^XuDM%@9_|nWq{d*Zu{DU&I4!0*G8_jGv*$3Zd?+I8yvjI4-U< zon-L>F{7=ImL3~j9(Yi7oV3Gam=lTs8iE_f;hQ<0hK!M zs)7f!0jC-`7pTGcMlww*aF7D2&~p>_U-yQb<{M8y06S8O%^>V6iWvPnPwK}}yreee z^t0)^ZzFnr9{`_e=O~%CoDTapeJ`~D(yup3Z38z1apB6HOJ?0`H=R0pgZNgKPKWRT2k;jPT=F zy?!FzUiD3)sUU*Rvl1CG2{0l+Wa$*gZRgb5@^ zl3z!S&cWOPF>cT>N>u3rb+qo)Tc;UV3Wc2e_6SrZv4NgPuRhT_lfFF8m7?CdCT%m5 zk3l?nCM*R+4QW1+-?iulXbaFrXe{mGDB$J>g~Qx8_KvLR2q?$M38Hx&@ZRAw#5K{= zvDGeWRiEYKRwb*8Hv1MUOJC$yg*BWdVz;pT;GP7$K2l0cs?_)*G|bUX_hcl86bl~M z@Hg6tN}p&KraBbTR$x)Fy#cOKpe4IuUtQpcb7EIcH=w{V8S-SplkSs82L{)pPon$v zLcxi`g*tBpcL!#SL4OXQ)*dNQFIe?A*hpeX9y{;c{)CzbIQ7XL->mJAaQvDw-+_f` z({zB9NE_Vrry3)WICreFsIuMTwO55D`}hof1@=#>D#9ByIaXZGN!{+b*C0|@?{>Pj z>s8UzZ}sK{7-p7QXXi27O@rltZ(PTsmdpdTXmG=7;mrH_I^w#iQ-pIxbvg7ta50~5C|&uh+pvwYZpZXBSobeml!?+4gon0;`#uik z7XiLU1N>w{!tIx9OF7kfH`MK=anq=YOJ3~$Fc1DEU9_CCtu$l$F^a}IsUHs8ct4Sj z?fP|0X7a6%PW``g+eK`g3sHh|Mv8pcHR@Xb=A#WjnN^!C_-bz{=>$WkJTe{e6cnP1 zgAHkKM4i|!mM>-2mFk(rq$4I^4~|(0KF4sF(LExr}nJXvXFAemMt^ zW_gDB8Rvu>m??R)9IvO>7zsJlIR!)HtE^qG#E&}loL8h&K1i7CEauk@Hkz=nvQem^$iun!|6ZL|D70j9HDJzhXPq7>Irl~{YvK?D1p>wFmj{vfjB1-!vf(y1SNap zF(=w@-1a+RbP!ng9-5tU^N%TPHi#HS($2IY3r+z%De!H^xP|p({t=aQ2;kv@21B^# z0u!7;fzZ55pM{_?Lbc+3$Z-LmuR1X$G?zMMgZprKh^46L#Ntrwnh;O71LqB`#of*bF6)Z!E7>=H2JWD8#U$2asw6<)#&6G483$Y(uiqRCKC%)cgQ(tZ^* z#PO4R?hgM6pbqfQNdii$*-z9fI2yhJR-p}6q)$0pqxxA)K*GLIc-{hb=WlCpay&(i zZH2wpI(_dGLVrFgDh!aA0}CQ^wOzaKCxp?%Xpp!adL%I-Jz9pVLgJIuoRvL$pTD~y zslw`T$Ng1WnX0#={S_U^PO%UmB@m=QGwNz$Go32TPq6|@v(pD7BeY*^*doDH*sjGH zF8wP$PjJg6NqavJF&2dcbos$fKaRL9V=BK5OA7y$AeI-V=K0lj;}D2!J2vIUfeY84qhbmd{f&squ_%xL-oU-i^ewShJ`!k9icu55Fq=b+ zdR*l8XM8Fdl8JT{kR-s=uU)9)a4jNPKW*M62EwK@GGk4q57}Y zo(N*M1etPxzqx~R3`E+4Dtx0o@KpRxV#4Q)NlHEr0!AL5lUdpVF&R-D_~3VMjy*<> z(*y=m^}_td*Rb7($7aA*tJ(w)9An=K;k@rVYLjO*qGM|x4OqTp+c!0JfS)FwIA-CT zbIWz-gBDg#L}a*f%Szn)?P144@6t76=6H8FN*-Q5mf1QGx>EQ;^F?c@;;TL~4kD(* z>K@N(BY2iO*zR5;ew5&TMN>?#Yxk!D*9@3}3&;esVW09_3LZ?B}K z?x=}=^OV5gAwqgw<@Vn34OQ|qnot!GtD7=-4)3ianSU-k%6E|$R<%`QwG=FuTdi}F zaF|9S{`g#3F-(w7`O8f-b75^aZ3zI$8Yw;FkCG)ZH??Le5??b8hpz~tJuji2p1cFz zf{xw`?%!D51D~zKV4>1iXt>JYtQ(TDJ*@lIH`8V=^TNZfbAh_|3c-%Ya+xNSZ=)JPgjcxx^ zW7;l`bHn0Lmj`=<0uEYOF$B(5<7>K0NriQkeQdXxuS_E;7&h6Mut6NOrU~HNUg? z>amvZ??R@M34ee@NZa5O=eTc)$Pq4*e%jMmU!Qn3{?Lw9t)XZz5&kvNvVCwrQOV^H zHkz5a5t$XQ^FzEJt^r6Lq(k7%Y&&^X_5N()WcR%f1-3w*)9`1_yR$7!VYu)uxv<^r z7SM5&!MS)fPz9sn7%_!M`h3=*I&f)dESX|D<`bznE~sG0U($5biJ8Fe31bxYlBBXY8gr2452i#(#OHRXiw z1`#Tuw<&E-+)DNE81*iD*)}YyaM0|z(}*wW*@H!pSaLY|6@k+$aIdQ_)xB^Bnn5ev zIVdGqk=G^M+8_TJ8V(A?Y1I(O9#*8(#10ANKv#QexzT>EoXjJ8^w#*A6BGaw8-T>h z^^-f-%)|1A3+zQBfPo4-dV#@(Z5%Ud#f7c_j!PySB|Pe6|9y;PbpHbYy;jvJALI0g zomK=s|Ad`T`L_d-3%&tiH(M!>XchTcfW``oobfXmHkk~&`ye@D~zZjVI)`qj*Tka4hg1Uf1!vnjPu|&r zH)h&jDM0FjDU>*ILs~k7ueGsU7?Q15Q4iFzK3m%qldl)_tv6i+b_^tHb#U)@6A^~o z{{Z<+)}X#6q49jrUfSQ9jZGZX4HtHH;sKFL{N^`YTek+O3%^5A?C1ajuyB={JDJ^Y8TvcPsgI8=Hy3gq1h4y6kL!&Mt? zrw-WnZT6UF9Tz)fjf59gDnNQ8y$54ko%=2|S+-`gNCY9(rb70AGGm3_NsYPc<8Jiu zTSY0M*_ww&O9_4ZFH~5ZqKxC6tltE=ZV#Nx0F!S%+Foh1?IjXlBx@8Hzu{sh8~%(r z+V8ZqkV2#`mgV?b7a@gXB*PzT_y*HNqx|Ykx|`8h`k5tteheSYSMZpUC4q{H-scL|^~re=xlecT2OHN-hQ@XK*L zL3T_o===$|ZvI>@xqk>}smGv;-?+YT`21n=uSpVjOGx)yc&(e%q?DcxdwEw#-8>HV zF{IP>gAzKJSbH1ty4Kj`{7=nks9v?s_ptS$ORLx*O%7pgjWe(~8Um45Sg85ucpWjW zftV|>JWqd1y(gz_us#0G^IY+|(~86El(R)VycJD^RrfFP*nOYCctNo-4~}?3UC@md zdNZZa8>Y&ND<8o!&|mdh+d4cxKzuk+`!_t6T|E~Cz+1cYaQaE>eUbfB?Le{Z6{Ur4 zym%ke7Y6}%eO>OM&Sl35)i)ofze@SRr@Tpr61x|PZ|$ZHG*sgndlUL!a#TN8cX~6e zZ5)+E)rho_8BdPcQv$+u|Ef+DsH>LQh`BJ1go2%{ywwd5DW?&hoMQQw^bgZgG$SK~ zRUcgiwoYAj;s0Lo_?M0|q7^ny5rH8o!^t)%PAlf`)dX-#H!?S3x=rLf)Wgm!mI3RA zW61ILo+k?c9>zR)YiR&Z1<*BVc*4qt= z*muzpR&+E|aoD9d#C}N^I7ABH1bbfG#5nrPt0>6VH=`er>w^kx+P8y+xA?7j4D91C zUCb$bR8(I4p|v!*IlV#ryzRaKSP{fCr+8OUA|Yk(O!(jT1*&frYckh95S*~LmlkE* zUj!ij08AvD5Bp^Li60fk@e+HDJDCFWHS0IJHkeK$b|!tkwqX3zryNdi6gMRCuzrBX z+Xhg81PyHNp{E}hTx8ElH&$$ziycs?*NW#j^cZGf(V>ce!PmVR&=yKJ;cWm^)YTW3 zPDLc??Ezcz0OD_jEkgiU(Ok^Y#SV{~_D62Av%&tR60GUGa3uMoHTag~5u$;r~x8Ha!{@U@Y?atD#m*Pc*0*`oW3M6!`$bf7amiKAkjAi16rn_)-Js+$dD zV05RzUaPyc#{-z@aAA;tOxx19ygsiSRM~A1T`HQbyjkEXvFAm}$1FuA7dP>~n?9lP zy~7WIbxv2AgwSvZ{AJV)aFZ1xH7RFXyP8pHykdT11ibdVzphUVtWVa#a=0w_-5crEB1;pPe?J9Wle3L>|LG!AVnVJrUz60+71{f zjC~3IFjGcQTq)U==?TuHa=3VOPQZQCA|F?a@e~XH+{Htq*bo`s1nu+^8tirORMKJh zJ5j$I07!$Z<9|1L(M?1{e{U90ObIr2YZ%|h3S9XDqxD=rnc+~(DoEf;(XEYurdoUn zDC1uGJs;6;#nSUi(01&Hoc`|WqA3QK~&P5oD+K|9XhEc0UUzH(tc-rv?jM0HJ&7kU0r>8 z-tLSXn4;L8<%p}xc#D)1fmc4b$~~y%t@j||8mgCSdpTtt`ncY2HhzHSw%fn#SvsIq zhfvv?f_GKsM-yrBC zhY2jt_KqTtjN%m>4a2iyo&4QE82rX9TTB~T_>qo=^W#@D2%X!-4n@VThz9cMU2pr$uY z{1-a7+ov4?2MWP37TAWdj5d`APO_5&h2$L2m4Xw1OjI9vnt@X-AR>}1s^&)m57R?W%4OQwSG<-nvs@r9ZE z-@NTbaMx&+2q3+chCzL2pC8q%GI$}7*v3u{m<;zH>HSX#DS_Zs{}DYRx`LdCWaoI+ z{X|NrY8_2D#)z=6gbUs$+JWS(wlQrj;%P(6O{ut07(p=%n9zOZ531a9B$!sa@tIg! z#*t614;;W)y|<|W4F7qyL3zx)zlWdf;#8o21^%wf39g~x{QhbJZj0&T+w%LCiT$or zR~gL=A&ZkFw1bhNBPkG05B#N%8X)kq29q`p%DEy*0(c1qUS}DckT;28BUE>ai7GV(*)ftO>ITU)-5OEcXGq_JW30 zi|vCu9zKm_bOVE#Ce=H2#b<$m)$lL_ga97vUnJbS7|HDnWFb|?dB)Bzc@b?2-b?73 zklA28w+9Je>kdY?H?Y*;8ga?-H;hyzArl@}_<18yN?jys_H_mds|6e>u3^=Lbn9^E zX8SZQ=SnGkx#iI1$ZrbBwnHWReDDwkm#Dr2`5N#uv0Y>xZ=~^;WUL~kKDg%2)lQiV zT9xC0`DhH{1w+JrIx;DCGg~cXIJBY|uyPxrUMtX$817ebYa_LHShN#}_D*V<=k`7N z72*u(CO^~gHIIn_I=O*3ASl?vQvF<~)pV25^H)33-atsPDSyaydH0nD9;MUQayW21 z&jr$bWTPRw=K|hFXBXjV3q>lSUy*@4I`&CU+X%3E=W<}lx+|)0*q$>vow}MLmBiwd zv-&+A!q1ZhcD~t*i7pS}3fgp_oRa9)&w5G@pANZ+A3pzh3tePp$5taQhmAhL{)%Mp z@y?iPJM;`H=UwGD3TE;jCk$-06ZLfE9i8d$IgLdtOVw@<=AXN`UR3%RZxGwJJ_-u{ zz}pfpeqjoYMT039V6U*_WgNVG@RTv+Mf&B4omlG@)-K-y-Kg`c{{bkim~u^%fIy4$ z1281x3HZ2|^B=<;!!2|nRWP>d?v7V&m4|eYCBcy5JD>_=(iT4yjbwoH<~}2Z_Dj1T z`RFf3AHUs>U!Q!)?y9g}sF`phEcy^E3Z za9f0XOlQ^PACcg3EV@tNtq9!MX;fCm2@am08Hxto;K`lc`9sXi)n_DgE&K@xVblG5%R$P>49PR#I_+r$$y#<_3P1OHtyO*3Vn}l93PNd;! zpnkV_sYVKx-ejaTN--1!u-jH?CJX+`H|-i?7$rJ)-j#bwtW+$onW1FM*1GP*rq<&m z^BjqxsgTnNSaC$tX$N^`)oFA5JSvR$JXk?|8(N8h<24kSW@z3p~8vi z$8|kT4{!1-(84M>Avas~7DOu|JX{~V>YC4ko1PIf5jo<+4-^E3+#=@iu}4MC8$Gv0 zd=B*F=wHRA!c(cmb<7>qA9BAt@TEm)3^2S}vWPq%8{<>PPmO7Jhfpn-Wq6pPiAW{P z&K>vjU=FUvmk8|;P)PALkkT3;G8#kVKXTt&mHrjgCo!G}r*%9RaeQNRt83f8wPT(V z4>K#SN;C~0*KYYoAk_ObW@W_=Ku&k(@2x~G2SaGSEX_o>CCcbe?X2n4(6WLdmYjqS z*2ZSiuo@@XnBw>1c~2oxLUyN{Dd&L%`8wtMuKtR&NWenvrcO#dB?TRUhHP% zNIfi=phdC&P9S;AZn=9b?MM9HlgnFysiPC008A)R&4RJ3mCM$S5#5xDA1l4DW@m!m zv#wKrgo^@nS&bh!dkW0T3hL$}e;L8HwNy4c>Tsq!Vp8&`zXc9v)}*xn*q0(@WKh72~(3b!-IlEwILpfV?+^2m zQ19P?o$tmUUmthme(w9`a5&s{xS3~$Q0aj23g)x|Jr;R2v@7&gL06Mk)8hRs^3@k7 z?&pomVXV=klt$)HfHPM_4(ngFe{moBeHu`NH!-G+-7XiOd zU`a4M(}^1F#srb&-p&HHTV;+fE+Q(8XE!m;q9K((U5~qg>i~~Rz2(Wrh6hBgX^*WY zLyY9~Fb?5<#fC@<8EN`^$vdHk&W~xv3t}gVvU5qdHGjr2GD~j@(>vEa@QSP#`L?Io z;Gh4JCW_6)=exaFw5uW3Ghp4=1Xch|WhOHrp4V>iO>p_8##A?IhiV^k7FxBm+5L&%?XpZB<){&9mMF6Z)>V+PCdV~Aeuo>Gg&Ihm&fnZ+#z9C5Ic(eMesOVbVIXYReG zvUoMb_)lZiP%`J77z3gXetJQh2Qizojt`m?nA?q5I!_h>47#+Li?JyqHzMG>&Hl-Y zcbtbrfq8N@hrn(S z^L}G)thAH3W_*y)xaL4M!0DXFt*o3XJZ^P$%c~{29gy27*-h-7 z`CZj6Us|Lkch9yiL^t6x4#oxdsAJnhtgol1CR39UL^@)A6P;lEmh1XjepQ+ta#K(2 zrk@YK6W3)f3Sb#GCThxeb>tylOgGV`*!F<*{-7tTn;bQBq(`Qht|fdb3uih>Puj#2 zzQcRuUl!>DwL$D^0(EArMRnUVdTPp`v_3u%s;A)@derW-9Aqi0jnFys03XT;vbie3 zrY41`M#^yaHiMgrI%WpD`Y!QTU#Su25Y-EdKezJbSH9XRuHRtvl0df6ENud|gEiSo z$I8j-vwMSkg{LuOk@az^mq-dN*+=Xj`Yjq@26^qm=#NXvh4t!(;Ug-hpD-r{`;=gJ z7e+JqzQfyMGT8xo!#J*T@w2itGI1}!IiA9-ER4fk!tu zE;Us9HRg4b0Y=M%k$_O9$w@?T*MIbgCU=O<$w=OSmXGhmk8{)nmF0fkh4Y5<)tAFR z%0Nuwkx7QKwq|NksjFJ!2d(DB+k3L;^0E2+J?b~<^9_pGDYXhI%kZ4M^&jMlhR>b2 z{F2_Y-rZAMnUUuA zgG}H!_@-_1jMF5?r>&f*I9!p`wkuS*ut_y)<`(p^YBs-DZtKDlf7Ap+n%2AS=R}2P z*UkPv+u-Iwf_mYmjsX^cBLmb;hChJ)>mv?USz0h)rZKex@oD$xm(KJ!xzY)Y3&L-m zgd1g-nfC+2lZr11Io?yUIU!d{&|zXe9RA}(ukT&`xC%N{Wr^+alsF>1S*mdxG^?WL zRK(<8lDwivA2=$}caq(a(LyWZ32-~$$wW+n#p({?W}e8xv@s+;inh}X+ch@-H&}-s z%IZTL=oTaZYT&3ej`io{Ge}cT!X^&H#onhWu_hqlS(lQx92>l`d7YY9YuO6eMvONs zgAR5h$v=l?dJ9lAq#;esFQHE>|G9O}eyujw_j~=CRQn}gdluw9|0vjS`UIngxdU8- z#j(&^^}IT46Zhts2lT`(EG7G9VxGj1J;?@-kDl*co;s+|0cRQ4l?$oo5jzVwST@n9 z+%`|6AWsZX*?U;j%CA@0`a>!lxQ!7p zdAA%x>UX{jHQ|S}@62!iE}sOm<w);aoUbzTGD(QrMMTW~kiz|)Zi zu|pm#_u@(8nAU!W*uGgUcl%+zDR#RaS+yxgQ&!0>anNRhO_` zgwMY?v3&;@#K0_a+&N$Gy;Dk^WN)}%|Y*m4K5k~8f>Zd`{!P{32L;;@GR)8Nh zaQVtVzcvZ#TK#n{b6_LIODPj0;Wrr{Lt*>kjwNs@y?#E^azwE% z5Pq~et>i$SG_E``;nGX6NhObWNILY%oh_oUOx(KZyF|(g;#QAM|^&3-hoN{t2r|qK0V{ox! zquCD)`A+sy*!tKxWZ|a163ovjpV!|J3 zhkx_veE&I3?m8_WTl3phYidMV1zMWp6_s=A_MgrM$p9~;tSxZI$+)^o9QRxtRp?~* zNpX%IyBZpwmcxIg2fp-xwM`7`1E)7^XnfOA&JDD^Tpj3Nfv78X(9DF3EN%K-?;Jk6 z3bdEQK*8S|sF3L2U9xpH+%A*o0VHhrhj}ii)k^MU^JeY0Jzx2{KpfskGI&)fbU}*j z1mvuNd45^(N`9}v^a)}BEe{Rdw$ZRygR-gqDpuRWZVyIA2hs%y`%unTDGjUbcx0|4 zA-Os}ZF~g4R+Vo6EN;%aZJw=Kcx#^OuZ*x?g2RG>g4(Ua+CatvpPQ8tR~?7fa<>A} zxo_4oGmj;N16rRqZ$Nz4TN*guum}E91`fv??`Q}aG%?HR4)`LA4XeZ6BG?QEdu|wR z=l!>Cm3skcTGkktK9$Ld$0pg0#sA5B4S_H+(_zpp_fpzFKlWbH-hKXl&JA7QSfO!6 zAHE$#u8hrhPYvI)>XF9XupS~*f5rm3m8sy|D@UYIP~U>z*cfTnlSl_iMv?iwC!Nqh zie{k}d^f^{fQB2`jfWta;*0*H90rJzWLJcdMXO#h0wv^}++4ct@7MRf zZndB0dS-CvFs^$C6yf$vD0IrRb@Vv^Q_6GRRu{O&zUNP6ixo`j4U3>jIwH&cc&#bV z!RpsZHy-@hG%r*0q5XGZOb3cIsw)*J(r;=XBS|@;6L_=PJ)hStg z(vnnCusni%eRDyJ6q3I1izt-RV16^0YS^aa@=(o9m(R&BW!MJ789gy@B29?{h0|wE zQDjF#m-UNGIy0<$>@xLDt&Oy#cVQ`TqW|@Yl5)KXU5XAQhRd=s}(h5Et? zTu%?{#n5^Szg_gmYiv4R_Qp5;znB6@4$5q=qUkjqh|{^j6EuSuNY?DfWG@b$83rtp zq%bb2jMYuD8Znpm2J7izr@?;6W0T1%5JWOh2S68(j^+}~cdQ_juYDKK6boN40o@8z z4Qg}romDwi-e!moQUr3DhW$kGtWFIMa=~PrnW6(ZGe@848K-E!awQ({)nh=yw!#CH z`1X@KD!xiWn#xb!^iB61=A|^d#>0~m+Dpu(7!pNO1z?QQHh}N`G z1S)fCQ|Myu7Rw`mlc*r@uIK`SkWX-mcPr1jD|CHqI-FC6E0!}r=LO>hlz;WxPyTVn z;Q2Sub4L+SOJ$*Pxzp3e&`4YffQy&F?vQkXG;Ff>=du-(va44lWh^bIF_NyBk7%8_ zNK4{MtD>K`C^pC`Veq*QT%^4YlM#>jz@*EEnSSlN?ianSw#LZoy%=0BRA*Q=dhEEp zKXn3pB5*PWDhV6+P;$)=o}&CuEeBVEMyRx*#EsPD{jYCDhgF!2NUVR6cBt&60X9a8 zZl6?aF{GcVUcu4IWY$@gfk>L1Dci&NPnoA94 z54YBrf;Md!55dbxUBo`*u_-6TlL3V|vjh^m#>KYc)us7uvh*Gfps-xN; z>W4WC+U?4rV{UXtmM6Ux(C8Z`Jg)PGuIU%@**tsj^r!i(t9$68FBJ;t=wgXI3wkj! z|M)=uC|*dcjX50=*VCJJKOI>b2;~N1$fer%@+BAo*i$h+2CTYL zkw7A2Sn``XCXK>ZR@7Um3K9(*xmH25!pggU{3Dh_I4$= z7Pisc^I-l_kcg2*FsA&OU>Mbl zSkSwD?8xSd=LBNF#9t$l7rt0_HXqi0m=o;wnXl4*sdo0gAEExCUNDfo=#;XMM)!^U z!O%)bJST=f?c~yg;7U+jIqS-2jP%iV{Af>*kfr9uTD~%_myIDR0{C4Hx}Ul2^RR?O zqi5J_?E)m7HXqVr`_`qU%doRItf{H9vY_wq{oyrqE8yW4qgvzg!6>$GXs7|Wcs&53;%EXdR%huS%l4ska6Cw3_mAe^>P4A1V7obSImoR}qK&6OS|F^yRKh%z z{N)mm$b^Ibp}ucdcd_}}`M~g*NGMYNHRP73aqj+L=+WH}KoLw0AY~-E?Q3CXJ(?ehyRQVR#)pxf!ieNOu->puiW|#?RA?Y{8MJc6v?C`!k5)8&sS5<;_`iG{x zKO?7w6N$t7z>t9Fb z;+yrX7WNJuasIMUWeXXRQ#P&$WZw(sYFBfB7Y>*)z@F@;&xTWb2kR$A z!Re>OO~5duWtIdXMHk28Gxe73luh&(qOdjL|ZjDXE0`7n6(5rIQCORV6bp>^X&B34EDt%CZJKsW#Xf|e(ht~ z*_oGasmXO*viT@5JcLyCjv3K9aX&Hz1?$3uG;12T+b@DiPwiS_ybhB(?beGGHZhX0 zT#nE1#8xl7=A>_lHttt&5%V3!2T{Zl8j5#ELAW~nXh7+}6=gfjWz0(!k=AFMhUK`x zVI+9&Z`g{gjO6CaMe~p_-Zwo+us$GvGyyv!Whe&l$H5Zno^XgE0E2Z{s$cHxr&dO} zG=1oDj&Y@tcnu=h?-NJ@;+X}-TZeFlEWJK3MZx=Ak_^7va%g-GL}=+mCSMab@0j>F zL^tY`H<6^lxX}3!wXuSDm#hG-!7k&lHjlOdu97Du`b{hhy@uex!u;bICCF}n$xy8x zXMVj3(>azm`GU}5iVU_BoR*{k4MIpM?nQz5dWXB6WB&2SQ^y19rKmQ_n$Grygz*w%A%3hW23v@SXTbKv85B#LmZbc4Rqx$S=NBO+=`E0nMPeLsFe5s^UX44I$3I z%S-g~i@`wvmg-}_y(|58H~WCO9EVXdu*x!~&pCG4%a;EK_+^Ou=#&#I3ljSD=(=1)}Dkf6JK7b{7s52 zMYB@?2_Z*x?MS1%c;bN&3uFb8lch%BnGS`4`~<*GiVq7JaW?_UC>;SNC1B!J*0q@V*)K&_>`ustp)&c?-wd{99%3RKBtImE zX2%Fa1;o8VmCjjK>BL))ex0pUrMxtGpDQj*3gtE zehFJT?8TS{@I0~iU_sj1=R=_uXLmI%kdA*98}sNATif&PDH^mpH;r43vm0c~ z|3#uh+&Sj7at|OOL^TjodGCwJ z9oMUpp@dVMbg*XAfrkc6{ON&rH)nIl$E)CY6irH{O%qGcv8P{YnYlH!k!XuqOkF_J zk(0nv2K(Kd7xH!adyQ_K?c3voMssgD70yfQ4QV07Etj4cr*pnOxL_;&6 zf@4gs&)K@4&7jkQx@(bi3UT$w>9>b}lpp=^vZGsr52wK2+AG$e*tBZamBX*B`h=Do zHq@sTF7r(X1aH8@EqEW2!Gjc;!4HM|O^-S!tqsL3D@FK~*gfK+rfUHcd)l+!o!j~% zmtI{q8*RXqIrXT1Lc3N{<6;_y;O2WNw^8$<^^hnqst6i?Tu1Dfo&W4}?bgyHBY8P6 zFaUUwhJu3J3u9#K3$)ln4~{(z#ImP#!~Tz?b8%!s|Nnp2b1HQ@DxA{ggpS!6!f~3Q8jndd^Hc;i^P!agZ=`RB9{fR!Ya{fKNJtwZehy9|D z6KaMF+7b$kn26-Xg1$@&L(3J$Rdsar$C|B=b?JC1gI&e8HK>6RGE7~wI-j+W7L9BY zh&`eUE;|#fYyb}+6Dw>ZPwTcbTIh&%!|+Q{VTBd95}g$9F%#f~F(DyiR-a&p&~n3I zRty1tF@}%{Dt{Uayr-o%V;U+h?|Lcr-D(+XYFpd^(7u^qrQBNY3FJdg%NN_iWXy`} zcXtgig>}V!SWJh?3KjQ)1q$B({V_kL^I$UM<-T?Qt&pKL>@T}`!q5vBAhSO^tU6$z z`;38V*fwJ!OwuWH9(8cd78#xZ4J9zZIuiDrfLz$}>XcqhI^?F3Yeq}+N&9C;`ZV-zqHrkF)iX#qO< z(~fi77(sVsG`>H4LiZW113rbT`Q$4`ezd}+8k>D>Sb-P_DbW9|z~BI%`32%8EhVCr z3ioFPF9G+ORs=HZq{Cg`K05WH@N1CU&M-~xV$5GK)P(JX8tRbTwtmM~za;u6iCKVm z13)S=lh+9L?Q;HG{C=sq*@usxs-6U=j*ql?^SoiI-AG>+5d{T8IXvczR`6AX+!L#; zv)RO48>*>}km%m@flmv_JN>b>KkBFuH=8R0d48J^Atmo4?pw$HDIoG{WXrf*Ml*oZ zZI|>=?(Cl;x;eW)--rsc!uR0?i@2aCh?hHiCqr{=_c(;Pp!cZX0Ce&5xO=6jw&MEv_pp4T2Eb;@Yzd??V;X$9Ye zh|qq)jaTI}e}6>88ieL(G_K%9YpO32${>F}_{9jr*+riW#JrD^91B+IxvdqSKQnZD z14Fb(N*i1?KCL>Ec*|1{py}N-Oc+zJ;4LB{}$SSeRyp$$ils5d3mngkXzR z=Rl_~4GE?A_}$&*UnjYQ>>ChqXNNY`!61{pW_}0!zM(+Z<%2Nh+0NCmPw@q8KoC>e zSXvDC$vN_bB}>|PJ;oK0UDw1GM=YMwAm}{FtOj|sCA%o>eI$nc--@?Ge;nyeQk9;d zm^1$~nNgiu7=@ECxqyJBRelMdM zY(ESP2vMm(rHfSyTuaRR3LcnwWX_P$u;r-NF4%CI{PA#u`VC$T7Dn7Zgc_J1fc^9O zCLVm@iXbTF{UHmi?{s%RnMv^lHF__#MJY8-P^BO(<#C6+T3@A@VvVta9U}XGDEa(wLkviqIoKqbBwe<>*E`T&}^*Fp!yEuafu_DFM?wC7Cn84J9s2tSw3FJ7C*HP ze_Dm~{UzuF2>9J`<_tUhD)MH9f1lC*=I{~STKc0QS$s}W12@`)?kx|&@iWgn(kbR3 zJFCuff?q9V_es<|pO12w8Cc1PixO&O&GR|;QqriW4mjHvp6b7XQO7~rwL?L`e4zB? z33a?f6@o-3I_&=0))S5b#2#CYU(_!jq#z_uV<;wEMIR!26)-ICp)Sg=P{`oi1w=;!iU@wfZUhqW3^{Uy!g{ zNuf-{Lrt?t7@AYi$`+MByML5ZqQL{q?#@fDtu>W1YycolbyOK#-mO@|l3wAg>=y5J zqopL>>F^i!P`>GJuMUHR(4!yBlHE@XJ(|z{TMFKf0*=5QeDlD2?X~;Bob62QTY33o z1`+Y`?S6sjxRc}WjjySjVUC>Co|ZeszN!f`)$z0v{7q1& zf%_LQ14gvjf#i&@qGL}wgFRg%U=;-;ljIHcqL=s%&o|kK>rjx~#_0QoC!>pr|1`?I z2^ChF{syheAHAWyOfz})JdU5C&j)VUDyT=4{wpCnOIq`06LV_7GR)4c&=n=YUd?;O zy!-B`+0bI-ViI>l4d)uHm@)bJ*s6xY0Z`!Ov=^@gOlWUX#56EdjiNK!H;t~~-IAXB zo1qn$!JvI>BlgUWR0fFrKPgAH?-lNmowYUDR8g4qSnjwlFZYXI*n5$8pX(pLf>!8N z*%MggZyJ{d@N;#EUOAxvNh1t0|G)p&S7*MNdI{dDxPSVT$-ZRWw>1XBjlvapjhq1G zv)cgwXc^gYhFCtXT`6c@0l>4C^8&o6)^IH4(AzLD0gOv68C`gP2bVbq`^)|F#=C(I z$AdInf3NMcpgedU3-kRqAJ5To0vj88_#lxFT)B1sfES7_A9jeT`W=cF2+yH1D-(0( zS#bt9+h4#zzE<$!Al5eF9NEzLr?D^vx|$(gq*DQ$5N~YF+v%*6yMUeI$^8`Pogkj4)IvkA^x5N?$5(H^ zUY5@2Z|-{AuCE*&wrZ-^cU5zgqvVZoWrwX?XI4q^HclR|prHOr6+U_u?ki=tORzcC zR$qky&BPg_Y_5)zKDxFCe}(yXwPeD|zt@@g=e4KB9060$7O-(IEvD&IRJ>j~?T?@P zgXtey3xTsDF8Hm}J6!r`V{@YS3%Jt~+qT2zHS>&{-3^Vk@;q07B`P~vxdxTX?YhUVAdT zF!MnRq~tK$m;(%;kHwZhQ~m9-S09|CRLTjC*_m~|LIBz!)%DL_R#Vk<(vb93#rd*_ z&L)L5z7W-DLMrlU*dzC`7-LXSWo?MjyDD)?vzIqYe{itCHfk<9^ zPw>B|ePCXErbc-AS*By0M{<0{jUWvZA+3~o{>JA0+Xt%WYwKFC*Ij)jd5;1foiLZF zeNw;_2|LuNT!&+5wxx{pWJWNeKxQBA3xjUjkvJw_tM-c ztE_Akt!HvC<;U99f6#H)=YoA)=bmje(L4u7! z!J70_$5`)}aFUqagk^BRV?kXeZ)Bxd@J{!_^weRKA*s`sd+wU%?F$MO!rlkzzKhPp zNU4O!clY^JVcHwo{xYaeyB>Yzy;x#bFJgbO^tmnjcq2l!9f9d18-Z%Z51Gd7J;%AK z1`7scJnT`M(@6{a@U6`7)09@mS=-x#*?D$MGh3w`Q-Hdlfl}S`yHmyZr7v$Kz!Dj< z1@YE5zR7RRok=H&>wbo_Ryi0b0FxiDoyGLbDXDumS6z&r+0a;=j4>-~x9gk*E3Pq2 z7({NK$3H?log0Q#Oe_W|0_k+;#Pik_8`<_~L6G9yd-yDR_W_OvLt(>13E3U0vnEwt zBmK}{vyC^m78XoGLUy1iqS2OveR3|%7>NRLGElbTH0Ma-tGuRoST-ETP!~OIR6!cqN@6bAYmxCsE4SYAWi+twa&*Y7}XMHDQmh0jztFNV?}qXk>tZ?EP2HZC&`b(#X= z^B~>o^V&{xwEf!mL>?Z4`Jyu>7JeCEr584#KBdV-CV#3oIejV!XUWJ*VK`vle+|7m z<}CRHW|F3zYUA`?6R5{HFjhz=YIQtF$5a7&Z!SZoG7Jgw zre?CyBZ&+h#snRx*zAmL_Rn=0LNfWt5VdkKOa!c^;_^l!)sJ~m3B{qKRQ|4hnkgXb z@m&+0dIT{70({6l_JVQ*f+;on^Lj%+i2`Y(ONzCE*NE%cgth%?lFL4mBunCQR{9)Q zh%>>YWsoG!1yVq2dtN(75%f{Jw*qvElN6B@FVh(cmweB5C#?3HDuEeZb40N%Kw6Mm zFhI?}gt+ihximvI6!l90%W%ce{fVj6o^WAy-B3mebU*^$PMNJ;d{)FMk8zH9TRKI@ zJ3i@$=I+1i6^69!XF7wtTd`qp+v&c-yuiS)!Z(*?i#4mHEQ`~(-p=MiaV|cFJU4aU zC>8PL=0QNzA{6?wz*q+3sp? z)BBcn942TkqS#_#TiweH$M$$iw0)EIEe|)P`%XfxFHXAlBJdceHN6CANLOsy)G@O7 zW8$m^$XgvVjrZ7C{2~9$wA5hjMqzUt^B3)>zxXh;;r8Hh711tMsti=Wrfa2&6!)j1IqT^-7i_FktC z#$f6M%)f4&Eru#RG7xaCa5~*xplNlR`;H@;Zt4T3j2oShoc(QO^EHuv#VY~jr2Gf! zrhYG9-q!fgCx=0JXyP3n_bB;GhM5qZ9(J!)4bs>hXV=1yP-gu(OKfos|Dp?f zot415Hyj}DFQEf38R&hSU29d-SKX_BNwgFIxNo)-B=wHec-5M9LssZGp4#=H+MuwYFKz{S7mv*s9z4^J(1z62HGjS>GfTGM@;1n# zlypE$WRb?5Um{)lK#l2Z;2M`DyOTu8x>11XpWzP0>?bw;`=?@0;f7}#im@eQX+0zG z8K3z4TCmRVJv?YR4<+rt*nIy(Qjk6-63~1=6MzaOV+(qe!y>RKv@W;}6g+#{Z?%nE*cdKz17$%+E90JHR?>nK&<<7Uh$G+3JgNF;l3R4*j6W zFAS-swY0a#p2mfem3AC9PUmvW!1hQjy`tS6h7zB%YyvJ~9XFUUGF2p+KwMuemd5Z5 zOGp`2@KyW%nbi=W2m&Bl`wME|m!&?@hqcnX?+e^CkQIj`?{8DGd}{p*xRC-)n6{x< zN>-lOOUK=x2`*L~N$_aJ;jy*jvC7XsD}IO&Ff*f3T-}&7S^K-4|Jq|3gCZKS$=2)TM{r6$f19MB$%N0N? z@GiC9=X0N2KJRXjA8(YlT-;>@p;iPGha^idiQ&k9RUXWbz`4^ejB~kTR)n#U3nB|J za^jCr6h-$L+JfS^t9q{Sq^LUTI7Yyp(ljri`iU*~W#<%@O~73W(#?6`i~Ff~o9%p| ztQ2yW2^J}VX`ULCG-$`wms&OEFZZKZ5p)~5L9tveIy2_hTr{yF$BMLXJb%&?Bo&S! zIq6u0d`ol*w*FJ`M+ku9%&b5^d4VxG9&@`24lNoE3|lbbdWAa|Z0$AYGUK6wvgjnx zVIUL(+Em@3Z2#WKyr4WzxD8*<=bzGW5bSV9?uCg>7uLf(B!+x}IZ)eR1?vx*jXLzm zcN~&qp0wz-n!-aM*#PcVf)~_Iw&}kpz}-1Y>g?APp_rfu6J0{i4~L9Ryz5F5LJ?8m ziqMxhU}yb}dP7-!{hsiY^Pc(MVq`iSj5oKfJfR91sW=8i1-0d`~3h7E&^Tj9HYH&wWb3wmEJtkv2YdC>4-`xi&I|dvI zF+Nsxi5y#g30{-|E_3?pAFg$$%)8V;p4>#h3z87^TXlS8apouM6(ZbTs^Oo#CFfi3>#lqpY4|F|7pphkl?$PnpFu_Sx@OH;)|}%F%BWh^!#MY} z=b2Z6)Iu^3%~Wf6HU*^E(%+gB=6&?cBLkt?x}>lLLmoLuysKp_&%L>|9eXoWS=aQm zcni4Qz)57WV>JR)S-IRT*_M25@&ZO0tIHm1(PAP zje_)|mz=dyS~pQx64~LQWD8(I@O11huS`zn9`-G&CRjVc6v`?fECEfzj2UM5hy5Rk z{w624HVkTb%JjhnBTidwoWA(QJ<}{15x1^CI;DcJS&fyUfb}vu*428Xa`=C9DeCoB zrWT(f!6jpjfP0UopVQH_FAHpBs8 z=#Vr@sFQQSvyc&R`w2J0Y499_rBs-V#5eF5U1srL=!5NjGh|f*7jc;I(OVEd~C2x~RLW!0CTov1w~dMnA-v&0F8^t7F^t2{UEq zd9*u@l-T&k7P^(_`eK1q&O{{Yb1O^1QNGzbkqtL3p52^qd5WvfI|MZ_#sKx8K_H`z zo;yV!`8AC)L$TI`@^&F6F$z!$VGH)RvU-OR3xX-HlFHJ--vc89gWIKd_^i(;fe^1~ zP@F?0TcJ)OPTJ(`d&{7I4T2q$EDJR|Y5t9)4w|DjE-pP^?8-UcivMuEl@ z$VbBG44<^&38;!#!O2Bdz=h*h)IIY-I1W%f6gs=aIzkRd6XhUSBy_$;VjAxpWeyT%#}&}av2D%yPXPMfH39(L(9at@fAF2-5poNdqJ z?aLeaz5Ry4?u<{ud<~g7DFOu>dC)rjxOr(sN=hQC+)FqW!&pQVD{On}gusUGGvO0O z4RgY~!u)c_L?!-grW%J5dEA+DF+O@i<1=c0&$TQXP2$obPhl~NjG6A7PS~3Q=jp@i zDY}nMJuGjK`FArwh48oeRQ_guy~F9p@G@>x$ql;PZCjb(H z6uJz40V`6(q(-}FjJ9@d$MwfYVOFT$mhQA!6kd~Q*bqN$V_HpY!{x|?$u1|J>JLUF zpT<&>gUq8-s?MKG-n+%p!zw=P5MmQkD!2=hjy1dxR9X-Xm-GAI84tr8>U-I`?~!rV zMlPs*!Oup50>H!yK0BV@30CK-NOF=BgLt@eNSvFH9MSaH`T?S;5)E1mb)56kv07xq zi6L!ci4N+X8+qdzh;M2HP6KVM`0TmsuvuwPniB{No*A=Q3~dRBGa2aWo!uuB4!%}M z_odH&ViE;OCzUb{hdC8VI(MaMsF^SRk=W;z8QN5NQtJFgwir^L(@C74hpB`F+#>r5 zHN~ox&FshwX>br^KM%}v6WOIV(PjgHmw#MXvpr68foB>6`9Sw1nDAR|^!bHgK-*Sx z{({$&X&?L=eUZIPq`O~hjRI>kLO~0qssUGPm3Fu<&4NaBX; ze;%i_cmyK-9HltCdY-ldqis82E#6=0^IMjc&-@cyfCP+kRp6c?QBj|BKjpq$@0&5< zj+dC>^lT55fT3r_MiHR6_QdH=*{%4jR2uw;s;>n&Vgm~Dp>K#pb~tAbptVa7 z|5&xY*A9~lVU^d%4c9{dWaAcsChLrE2MnIMo3c-1bz0(3k}gqTpv#X+tXK49By!ul z9PLys$xm&v0?o9@ay`Zcn=C)-T|JIhgU!kG#-4jEVeg|b6N|BLivDeBgs<&)qBqr# zDk~&6!vLd+@=aa1aS!tT=~4sKNE0ewx4Jbb`BKQDk@uKT0Dlr0fqaAoeaxn#EBnK4 z&E{Kmi~}4>B#Loh!}2gK8uV+xUZ<+*dE)mM*Ym{R2g6+!WuTyx_yjuo{UnI_vNvS} zEg}ucM4;zppn{5QUj>B1Gp=2c+n8AP4Q`bWa=?b*vtB=xbJNdI@vNBQGt+AtG2q*F*FF=)k>q83WmE5xpW*VTQ|<^G^R@LG znP1ad!l&Cz`|F30W=cc<84I}NX9CsG8&rnN622d}9nx2|32uZn#LJcOTCs>NUt*_{ zx#?d>?&|fJ1Ug~*swWeqn#M{X$?{>#iRQn#x)H1>L7@p%O&G^oR;UtFY1Evi$`IgJ*O|HM0H6yaJ zqxKxi#8@HiL4L)G66;JD$SsnC7UCc_ z$^$mLbVG?*>Jn&BnP#TAHtc+;cjIYOqM3#niru4`S|HmfMU$;Qx2-=Wi(2#QvWyfq zk6A5H9P+laRV`oh0^qWJh10DN*Dki-KVa+3$RVb;)eLq_6pkIZ(55#X>wY zpgE!GVA?~~3%SSyBnHp1vU0u8$yK8Gls}TkvGvkLu)&0+j72lKbB-!h(EaA&&NjU}x2pvWt9pY0i2OyiD!PkiWJVA56Y%oxo@M?NCI* z;q0$Fva9ijt`qT5pjnO%tNr=EyN3|#f}1D z%4I&l>!>SzLGHEcY3!ff_Jam5g^yn`;Rwaq(`TwDU?*MQu392DQKP6i`g$oBg7iw5 zPD{MH;lo`&5<^)T%y3^47;c?P!I+G9nv_}$_V)?F{nYVRxRXL0?@w<9lNZjRtqZ{6 z(EKUsD+8bVBoM2)OX7e(aQ{s(wXh=Z5Cra;j4y-( z(nfhr?kSA1kCjMx0?aVHplIuN(Gl6sb~e(eWE8CxS-Y=j?!qfU*5P!n8T0M33WIDj zT~2L@^zpiclGr{Xw?I~Yc}N`d5TFS42;7$j?^bPo4f5w_iAGVfVK5QmlWdzri-;v2 z;|?QTxQy;#r&9Qe5w+JY@hEtz5!e|FFZ3<%#yBkMkAefGU=a$f{U zpTPy;P(sDk@bYZ0M;7TrOD@<3?Kl6h7+W;fO{|+);t3>iMn*sXN@u*yVN8V;{48&^!C%dW(XDoBXYGw|BnorF%N=TU?H|tI=@H&d}cW zJ`tUnwYA~47lT%;R-q=DU+1#)cfProMWZhP11SK%e#m?kE`1FEq4WZdo{ocOh8~^F zpHKM`UW}}l1}z`LoO80T%=P(OoBh#Ygu;1H5XUAGw*Do^8U@4E+7Ji-5uAo{nsx4{ z`x0l-Q}orK1p(DzZ%lUu&_TPzoKrs4ejOc);pqY-Uo8DZJ>zK6Sr=mE4Rs;_znp3O z(jscB$X;F`a<@ABT73e&?gZ$p0k0p6WIo-4FCsj$Ke*Tm5TtL8;K71{Gp29*TQ`Hb z@b-Ld2ODS^s2~wPUKwBVqUrU)GVpLp)Z7i?TZte=@|PX@cg48^xe^NYa_A?_b_D?> z=kKum-^6b39A3p}%9c`zN3+#GP3{qu6MeezgRtEF*HH{N9fl}AwcI1?n17K(?E`NQ^V~-dD7>164$&1C>>Nw(= zZpOOpwWZ;ao~vG;Qr|kcBe}Df4F><(sY{kuc%emrBMdaG*2{r`6z=rN3UE zeLh+IEfVqZ4`)Yc%tze^Fs5Bl%O`C$lh?WzqkjPtcF38?4PY1#j1#p@2jK?o^e}a- z@sutp3#Y+ZbiTbP1e~?F?dNJ&>%PaWo-hlRJ4dY4sREkq z8G~Tb%{{?2@_h=njm3qDn&#TB)xlvUnJ0HFNm7ei&_|X}TX=+~I}S9v+ipe-tZ4;j zv_@}D@wPAb0Cq3Qh3B+R?JNc|ksc=1hWFo!#F9PS&dbXw31rQ^_~>Y2k3>HDtnuwo zLFDZvw&f^l@<4wc8mt-&9&^lcjjxk|cu!s-FbLiYy5hB_g*>Av4cnFrRxdri*ioQc zc}8H2)!YhOSbO{u<$2hn*0`jC^%i4`fHZIh`VFuGWIiS&nf?th+WE^A{%d}jXrG!+ zIfNQY+2Sq{jgJnBF=Eg^WyK)>-aXt1KI|%3n7$rea|}UK_hRk5 z`V=+-co1^VMLb$8p5MH%g|_0bn~1sDPQ+%m9+1%rrt%12xHpla<%wC(^Kf^R=JR#+O&!!{5NltDOsXe0&5@VTMAVDTAp44DI*zdoir^ z&P}=*S#|d>L4EE)8e!>Em42}{n!DuFR+;-)lsARbK#pxeZ$FFT7wg)1Ip!8N?iT_; zic%$l@=y#+ZUpAN=Ighcn-*89(YgbfvXzNfWFKRprrF?8p+axo^UT>f@5RQ6qa!1i z!ODFd{TL8dV5h^@qz7?#8IJYAL8ow5^u<7t`lA52$I*wH!$Ba}c29UeUsPc8; z4`xGK&n$}xA~AM+s+H+J@nR~){dI#_wf)hEv%&bfaX9&$a=g#7?^q z@GiT@*DFMAbV0^HiFnF2w{LiR=RRR3M+}*|FPv#(a$8{x}(sg(o4ZN zxe}-8%&?`@B94Xe{uB)-;N{-fz@CWnz_vBnwbs3L(?47H4aV0g7?W2EC18d}vdXgG z^aA0qd5c`r{|E~b=T+6($ERQ7E14`so@W%SntJ}smI;5`K_%Iqde+`QK66m%1)hI< zw3k_Aysd`GQZH>N**F6EIE~sdei)_wY$IbY%nKSE@3oyd>*cVnTZ+9Ow0L*zKc{?gD@>d%n<;XDF2>z;6o`jKaJltk zh6k#4r+T9h-$BDIjS`(h(i2;ln^u{~{SF8dfk_(J!)YPE`L=To-Pz}L?xPA?EfBJA zO$ys6c4EjIe(7-FsZdE&Fx@%_bV9R#b_Blzx%U8o}5o9H5_NhqV8&ddP(DmV6^4g|7-{UcMYkB zy6F8`%>tl0TlwqN4nj`M?8p_|G2jya^RR6ZS*e{Q8>+8;>O*z&hX~J@BOk#!7%s?) z9Q}|T4f(UFm#bRBL@8-ok$60a2v;*^M(-=rpm=+kj)RyG9H+V zUbZ#Kvf^tboud~J{~ABm(_Bwbxe-aA%UlS)*cVG?(x5YcD#yP=AZz7cj1sEAs#db= z(MzzLzWYGpoOw>6+#$*bX{q6NJ?jwKjrMF4u~(90CO5*D+X1|@T;&)+1%GL`rnUWU zf_iMoAAbv{k9o$}_L42z}uSADgkW{eYv&PD9U3*3HUjdadDi z%!Iackk59cvF{Q+9Dm-{Id!SY$I4j~22L`c^t@S+AuVAVr-)dgOsE0CvD|l)1^ejU zLk$=X6qWsdD}Is`=vKQsnVyB_RuXyqf^hdc&Ca@`I^Ox4UDi>-+z-#|nD8pFr4$&( z?2I|JhWqSDk@HP;{UBvdq4W3_^!r9BieK>sNZF~#JulUnDrgvek8|I(`RzmbAK|(g zh8l?ZV8;H9PfI7eCo{5kJnfOZ1l*j-@=fM>7B>P$-8G0*+lQPoHJ#=Y{&f7=ACL-_ zKmBnVn*%y<#lVd7_+R>pJOp)fhY|$>{@W$?%X9o`yQa?c1wzi3DrUS!@{(3#{cJ2& z53HaNxOlTuU||HdV3G8qS%zvyJbfgjqXQS&qB>9%gMd1r>bD;^Q3#kLdt|6M6lL@r zD&6!V&Q&C2skti1iu1+XTOZwjQl{5|-SD8LlYA&*qkL)-kWPhDx_Mr;$QNZ=@z9-Y zB!U(e>%KoxHOK0g+$ee$DvoHNodQ(6V@8z^$hyzm2mwV&mjOh_k_2zvvRkk5ntrI!Xb!{VKS^B2;;jSB(Z zccAe=3jd1`Ua6_V3u+*N4hM9F@k1`@Vg%dmi$$$&(CYABB~+jBSh37&SuM9v@{aLo z@JywpG}g2eEj;oF90&BM^!^lNuTwFch3c0qLH8Ay39o9byxsm@zF3`iW~Hpd^I)r+ zAdFa1Gy&UqXRAGW`H7d__~SzwiLPL(WAm)IF6fHLO|6q{lL}SqfGLZ1`(uTScyDx6@mDELxkxpZp)pRu8~l;6u2v_e3h4Jl#BbUQ=VLmXRBdBzku zMP<#zmM#1wsQj}D!Wl%F*UQ*o8~mnaRe^dB6Dr!NcK}6cC4jnz>3gFgya;~e_JuXm zySqT1a`o)W-F2pSHmVH=>X;!;Sidopk~mXNXg}oTQ&f~-7Vcw_(c2B5~ZV`4M zq^3LLC`tFPR}|L?~Um#w7-O=ZE_JEPJn{_i@78iBHJ~}a9&u39s{nR zb6P11Sh<^5Ui$t@z};AD1grszyIqjOu&3wO+`Ux@HA;%JQEtm@=XkJ?4 z8>7t|NDYHZGzjdHV7oZ|@i<9TnmZ!2?sf0hP7Xj-8bpNxh5w2qTnJvc<-pVX$lgm~ zL`bh1tb_$e_StMw@sY>B)E}A0!gtSK-KXr;9f2fW;;nbJFqdZPtKI;fc#J02G8_x}+H z=;fN%)^@;V$t>ae#dEC#x**gLaF~KsHqvpnb6-Dg=V5{{#3%Lu^)00_q8K|k4?Mim zcd=un^7GKCkrJ>CQoR4is5XHE@Isz}&iQ)9+ zN!G3#^65;Bnwu_)hV>qIA^Xo4)m(0$eQh8i9wv%GDk^%*6 zQ|aBTgh}fMd=poR{VbEmmPAF8S53@>Jh2%(N~=T=M0(xZ0%oB)!*LGGp(H@kxg$SI z?=i6kKX?WmIg<1hM<$9;?Nh&B(e0YxDqu?bw`K-=cU2;S5Dvn^LCmr(U(8K<;gB@kq6 zD)AvbHf6^zyVRz~>W62AO3*iGe9suJlU3dK(PU^?2xRft9S}34Cv}$3oW2U-Z;mU! z`tVJt1!?vqVbfZjT1~8h&lr{(j}pc2Wn$h?2;z}7K@AeDOcb*~OZsGE)7)|LcX#D` z1|bMZG8umiiV0g4%;Y7;TnPV!Eea4aIQF6A*1y3toW^1t_w4HTuRSR#^Gsx#73WtW z3z1Rp1Z;GuhHmb|K6fBKuxmAtw3 zH`lDZGA9-7Tq6#xs5Z`*B zGx1y+!?vG;IL!E4_6@Q@EDwg%J$4T>&zpJwNCvizR;IHZ<6}|_Zkb+vcSYgYQh}9h z^RlYLES>4=Tc$E*z!E=wH{fx3FXG5ZblK6mkXv96xOg!LIMCFD7`<)HM|Z3JG$)1A z-yioi+AkW}+jlvCp<2ZUg#nyG$)39uN|O3o=ucipN_tdXfA&{NCKn3}G`!k`@E;nj zgFa_|zuVpMG^Tz68i{!qC zWa}_8;j_-sxWw}p^JZTiy2SG2tuW0rORaIdV^L8POG!>hsPi>^Ec^IkSma^V#F%rH zv0nyrCt~U?TGt<)n7PgQiBn7uv)8TZVY-P$p-xp3NEC85^~ge7$F0lMxXoKhDBW6Y zC;-MlBgUsp+p_#H)R}_K$UnI{y5N0blxWHC|3iO9EL5_|%L!4RhVAMY4?=xf^KqIp zeLSC6JEW{~B36I4=@d5T8ZY-}-~kT>yzg(pjiXOTS%Xi{dlR1_JXp3=6SsdjOrU95 z*5}wKI#SY&(xNvYccjzjOgJ4ZzMc&TtI5kdH)tuz5sWdv%k|9XW%eF%J;Km}Nezk1 z&`Rs$kRKk49m)ho^vyUm!$oTTZ(0?8 zWp92co*lGgy1vpWdY4O#zs54NYS){W4N{-^YC@n{Y6Ku0A*4|xseS7xqP`>{GJ)xn z;rYe+;Yf4;UCxpV;5IA3L9@yK^SgD!{CZn!2p=blBA9sS%mv`z%Ypq)*~PkretkZK zL-L-pZbY?ZGy*WOOatPj;~!k7iiE9|?L<{Ct;mNCz4~S$=rZlJqA%HKM-^?j*#km> z^CJ z-GHK4wtEEJ4vx9TVvaP!bCDX|j%rh{Mm_*;7!2MJGG25Ux zmGOn~g|Z?BGWiq}pI3g`Br-@qFD?x$#`FpCUoENTqu=un|E}bpw`)FlDrx4P+dSwW zW1rQ{qL(-c5%~jh;jVD3?>&jkPFCyaYol%EQ3WyP=$G6u5eh&5Q0i&qU-(US}eyta`)G*c8Cu1xWAop?G zNN@^az9Q>k8`VzR3xXGzYo_-xLEo>FI(i-F)w>`b(r3I*d+ttY-o9HFQ@0jqUo(rcT8^O9o*snRuQN8{J;>=m%$y;?bVoWgD>A(|AzT`ijSi(q%w+?5+?2^eDS z=aBRuBe%G#=5L|UcCrUlq8lckUDM?I^g>ws&B-eTlMy8{H7W|gtkrQJ-xxjUnm@E= zN6wrHWnm&Yrc5)c zZyGf*JsYX4KQV~06z51H(X_Sn1ykp<9#uu~6 z4`t!HH=>%0XPcU_@;t`U*PvytbQ90`b8m3U1@{g0V4Gvyv*q@-?})IIugcxd?r4o! z_bE=;tTwXVsMLL)f`Sbl$+h={HkHXyLK=XoXbDIcuUu!>uQ?F)kwF3|V`!w)+g>p? zx0x?uNlhQLf~Hr~hi^3FtX0x5G*3`RG6tKr=w=tMltwfek7+1doJ3hVCFPIq`2$5K zezxT(!8mbFVCYNTN7(aF$kNz;8T}b~K6ICp^>MSl`$D+C8Xcx4QY}W=S0eOfVT)6Z zA&-kbol)M(zJ!@S2R161fg~!X*?-bw60I`_X;U{#1zJy@X%V0U!OT?tA&;AuVNh6g}1KM+Dz%So6tM@r4ag0H+cjYYDDnH;5+80zvr(m1F0D zM+&f_uo&}Ybbj8sAYlA-ar7e2o?43nw8okpqdm_5Hf2cC5{Hnx+U+m>!6|F6wXC=7 zHK)SgOfl|M@xl0BVg=-9E^$G)jRU9;0*M$4B3@ZhR$5Orp1Rt>-`O(@>8$WvrSZJ+GiI| zf?3m=w@z{xiVIGVTm+pR6K`MQpR`148d2bUq!Y`-V&2e(B8m)4Pru8W9B-Jv4t!d* z`RC2@6T_qK&>2O&D*SUSPcmpMp|Rd3)`9! zc{hcAhK=hfKO?I}^f8}Hzvgj5(w66mD*IwlCp>C4 z{)6E>IN*ycShh2?VWE)!az5hrq6aGi3R3;~khL7s3%*{0A&Skfh&y4@MZmj3APd_i zm=x6!lyZp`o&?%Lu<+;ApJ2KP>4$RRZLLmTo9YJZHG8qJOBBo9F ze;i$VJk$IC*ZrK->7;NU+>rZ^}OZ#;Qxj`$k2vHEosQvi4#}5*>?U- zN&I)j+^h#nFQQ$e_Dt0d1`s<(8aNTo%jVCFtyD83IX5aM(4QQnV;D({@4T7+g0T3sdrGvN9 z1q&n}Hg+RXC~Y=0wQu*+TeyQhD*FKilLftB)I#~`y1CU$G(pKH#l)^sNNrEagh{s~8&3?1 z!7(+~KVlXy+givtfYql9ynOsiL#%@MY}@u{#Lg?X0YBi$sjF$yY7Wx&2!bxKP&x#! z_W@ql)P*RV0^e_ZLHV?^&q(RK zD2*iMC?v0LxlS5GD}$Zu|NoL5W7;`rldXqXuLO?UnbC0oOQQ;WHd&!FcWO>{*;D7PwYtj z-xr0z>66nw$;?Y*XlT{X&0xrYOTXp!5~mO?kdF#gogU;LKo=e6p7X0~z40iVj8860 z-`issh+XP%75(|v1Pi!4xROxYLW&lMJ*cVOOb^Q1>zNFmeMohuBf32qtY}Z@l;ESf zLRzh6O3E++G@9|Uss?|uA!!9qYprHtB!ka@a_8z?r{E1&;hQ*?*7^Vf#NOSI6@~ac z15igDCc773Ch(SI30>S#HJoU}lJN9qnmO1Mg!)rM%6NWBLx% zV)sp|B?>Ev>sgAy2`84fyu8w4E&|QjjN)~1LcW^g^`8%W19YUoA^$e!<}KvRN_FA~ ze|FI=*NmAJdUC#2SEa`6dOuBQ(}Vt}dB@>SVL!?9twxP$YKAN-q{)79 zuY^W#r$O(nJ@)0ExUXaVNNVIvGW1_xG-_a68%J%W3@I`PDHi6Z=-J68L%im%n%qa_^&6z#0r$?q5iZy9GJ` z-B(^8=`ke5>d@<@g{y$KAa>sbpJ$(;BA4p=qH~|*hs%&4tczTmDf@ET5`dM=E6C^9 z3rSSzk8`FLDUX;rNRi#n9bqvlK=pnpLTd@k1OL6u@RVfPKlRT>Q5oXTnim?YJ`Oq8 zt=nf*rX>#=@iX12%+;t@6}ht^M-y2Jxk;|%{U*79({S#7UReKfj{zV(-+e(v24}Xn z6f?0O(}3}jh!iu#;QQHatU<3#@cYKp8qbm@3QP{}^A_5zG=Y=@H5kD|*`mEcV)Q>q zz)j$u*R%==DWyGcO&ew<201EbOk`VYr{Vdp9(-KV2@K#+?6^Sf-=DGOAM1Psn@<_q zB3$HT*c>~WZjE5HmT~EdEg(|$JE2wUvEA>1l0x6D)9YUmcV*;aC7X*fIiTJYyPa-G z*aui}9V^3CR-&+JKNY5$I;xVe&hfqn=I-Vjj5-S2ACDm3;SFmz5Pt}SD?^%j^q4mx z5Kae62Zk$HAqU|%Vs~FAZ}Z1F8(8Ol^X|x$Hh-aHr0UZ>;z@Co7(0k*cvMU zO!u6tGtuCS?My_oqR2#_*hWXgAXmEi?{vaZsWn|*u>EpV4XQZo0o+`L-N~O)gf_0H zLDUpw`|sy9NBCKjsN4)DltZ0o*RZO0J+8M133~cD&#LJ^rM;KwT1TZwV}6BYl@SJW z_~Bd8u(S84An98`kdZ)w4W}~Po7x<;a=pkccQ||lgJW(YLNpjVbq2SLH4~Y`=c92| zpi^&L%$C=wgQf!&kWRwK25pA2x8-d3PYGfC4mT;YP6W&bVz8*5h;-Y~oE4Yx@d<JLX-nzxEk_>LFw`MkvsAPHiE+sM4kZV7{X~% z9KO+_Q5&|FGHf&RuJw7n6i(o;-~BP1zXZ}NoTl=Cw zrK^6OAyqLVFbZ^eE-)_4w}Iq-j2}a;?UB(z3@c5SFLlB0VVk>(DVK)L8}VehP`Xf_ zr4EhJc6t0)0zb}|jG^q=tCsjc~? zdEn+3*X_c`(s_`UoNGt#TgoTL5gfc!Kj2;WtL?E((`{NZdMu<^v4sX2(<+kSdlIE< zMy{HOsJCJQCL=Zn6$(!{ZSH35M6F{T3V5@Ap9b!*%JQjeQ95mXFqIdB_M-0rtLQjH4uP-u zsxR<;Z8676J-YvaH9)t#8&q-Ns>gT&<&fP@9TJ|<3{ErvhV6NJ#TNBQqY}je8o~Rf zN3^7R<31OKQ=OvC5?4%e@WNbhP6^)F#ik4&__dnTv=th#f{Sndn&7+SFJ%zaQmoJc z?EjRkzRAdY5Pw|Ur`^cD3TFm@4P}u1zN(^3O^KB5sm60qAp_gmVHRosoM`Rjr?RhR9>`5U%_U}CanHov9~&>=PiF0fE1 z-!#sjT*rNt-8UKrKww-=bNR4AL`}cOJi6J^pPQ8`_KuA2I}U=})6c9Cz^mD0U~z7H zUzXDEbn|YigrmZ2iRT%!qu-P0{q_M0RmJ{OAvlm2cd&WG{$8Dwj6cDRW=A&8sf{623+&TEktnj2F+}bOBr-N3OCw-jCZb~fq+^~ zG1G!{ZN@n0kp}SG28->L`zD>1s6d@I;6wxkJwy-6)^uN{XMchexVRSL|26WY6yyH6 zW_tvw$Tu^_Pgj^nFEbkElJaoE>BdG--|yCLAN75l`M>`)0&dQD6exNL7Q2~P4eXz1 z9w$OqZ2-*t!#5bKm(pNpBs)3R-SZAt_eEs5q zT+*t%aJNYIp45tGbK2?v3npavY4wv|aq>y;Py@6=zw(pgy8zmVjyFCJRq+GdCs^h# zsYJ>h&yOklK)wG_3EETc3)auJv>z)&PF4nIpbQo3X6 zJNT(8?{Z5{88(maCeP{gePU~Axf&4HQtA)@^*It~;o(BmOZ~O(>>J?1MTn?p$lxfS zStrBiDcA}&bET}WAHU4Yy{FyQrV_j2awZ+TIsK_O#A0#Hd{OWA=AqLV+qbe^USjh*2%OnBvp2zSLD!g=ii?hWCylobAsOmiJ`j zU!CF6^WmjYNaD-_CQl8j%f+7~_;)!K11um@$-fYhueuZz{W7-0uiE;=_Lz~sw zj1~j<>2KzzJvjMDPnb7GNTWtGt`HnL+V7tsKhR52_$*;$-1VtvB3Pb*RY>18tN^XL zR9wa3vqb;QH@bkQ6Pt*l2km+|-+UuP)QkYmEsX+utSlB(1fR8S?jwurIGRq7gj&%P&VuvU&{dTz<6cIG3fjsH}9k?;L(U$8Z`kxt2|RG15EjA(RV|4UUa8E{;-fM zc3QR5?I)?=n^xjU>tnc=*|A~h3Ws8;{z`N{Ebs}O5}^4_6`PaWKt^w~Pd5kQklx?) zJLf|~lcT{?LeS$Bo5@Ib#qes$Ls!-f?Zl>-Ah-1Sft@x+-VvA;=t^%Uo(;57s3v(H{y-$5qiK@4s#W9s zG*yhF%>6&sLX7#jD%G?q(jN2hLQ4Z0R}+QH1}5UpAD-WMk1NM_@1$o~T24vS!!3d3 z!}iAd^?ODA(jq{;`!2UR60!$C zIsL7C;ZavXcT?q*mTk(sS2m{iUozAm1o+N#;1Mxx)~85aVsSQ2tDeobPnlRJr${X} zN-t@0G7TjA%LR*Si$uPzD0>H8%rHn;;Qvr&h$c$1ltm7%(;hvQjV7|4Hdt9y0kv#- zThdbfh>r!K7ppr}o6#^T#FJNz{Ls#}yOBcID=YA0d7<{SJ@cTtqA;L@Rv%t_dQiPP zYr%K%b*RVrIVUx(G?FJ)dYK49vB$`%2E@Rohpxfx-RQO?77;vxCE!Ua=K+g(*4q%= z-G%2!L55kFfM4RYx(MZ`IgIKFkw!9FQ-}%+7e%iM`8Jrlr#^NP{S_^|J80;22%JnJzn-Tq|Dk>(m zYfujeW(x{wZZ@Bu{8Hr2=5g;R)arn_m z?#w&XrJ7ojc`Yq(jZ!C+=RR}7dXkb| zFU*Jx@`?tgV?1wB#s{i|AU25y*7`jG5o%*Oq2V4ETw53PV3MW#WVld06t6aq>`+WB zLoL$k^2?^(OxWYf#K+z!zqf`}a4D&Cmn<#<90dL5s~9i8hUz|gtb)%IyI;y`zQW^5 zU{tRU8vN7pn=_oZZ9Ss$*UP%?SDp?6s!v-GmJmUd^SLnG>*=orW#^YbobfOp9y)&u zip=AqQ^*ja7Ehs~3{2{*HBze!3)OT2qp-k5oD64U({)B?Vt%ClFL!~7h$qtQQgM7~ zEeN|H^&Ob%x@(-hH(H!MZ87BzcV=MGH>>(>Q!yep0w47undjDSWSkdH!XOEQsW$=S zf-{ohK$eJKQg`*MwNkG;iazqU?~QL;%R?VImV-f$7DVFPW@Pn`Rof1F*sxLAxM0MH zXp<8yiUsH|qLxIHvvZZ-4|X=ul4D0)y|22R*th>vFTP2SC4qE8r+Cv6l-n;0hYpW~ zeM;LxsrJV(R%LW>a5RNpYtZ?9!BQmt8T~j+I7vO@JyDfHrvJNrO!~)Sv-HcYme(xo zObVs>ZX`9QX)W4RzJR}#j*VF$0Pb19Qr(q;uPZh5XFw?mtUUl5JM^zkDsJ4+*u;or z5qb)drPuVKv0iGJN)3%46ZpT|?^TdJb$%E$=2l(iE&(6`y` zJB0Q~Ory5}R|L?|J%0!txk(-~y6I}OYZUs5=9j5B?T{t+bs) zYl>a>$oO=2KuwC#CB|^nPP;mcp}9e-G|e(l`c=7J_G`|*Dpvi`wlTE-*!Lf?4t-R2 zgA1ehMh@t50*E3rKR8GGbMC~KyBd)-rRL7Ocdhx}LVVL@^z~XH_O2KlGc%)^=pdD* zT_RY~L(?gINcvB&rV)}rF|pks_GwldTA{-x*XxWA{}V2+j;uMG{0^zL4DSn+(s1CZ z0gxc8WqDhnIdmA#*y}_-Q*QyhGcJQ^aQgT(f#kP_3vwYv`n+z;w>(O?)pQsuhIIlp z$N4g!V5*ugdc`lqH?drG)RN!yBp^joUSD7WPLCU_qfGYN9hwXnoqO#<4b1h1IArGF zzveDf)`gBws3`{oRWa`F78?>PN={*C&jUBR0Zij z-FALe8@?h|Pl*-7Fo;B~hzdn?jNLs$)Uvj-uJ4T)HHX9HEN&~bw#XkNl`0E%+f|;^ z-A+JobyKYHYJxFFD&wr>F;cTMHF(;2nl_qh z*Dsrh0Tm%grsu0j^;dlst@&9fp7F`FG6DNDn6)Y;R+Idg7zKKOX!J&FDJ#x#eNG+H z`NO4r?a7;&l}$Q%xt9}za@neE8a@>quGFRGy~c*d1)gy=Ty}eJYu04@XFzg=0;_=W zg_+Rm#6eP-+CLE6k;$8Ygv|yj9v>9ei4@F!z|isJmc3?lw9C^Qf&aFN;vp|b%$med^SsX6t+4w1-n$s*>}?kMgRe4@pK_Hy&)Vcx|LuP z_sKgjC}G`1ogZ49VV5;KsM5Pyf^qE|q^}Tt5o2m`0ZvPh-HE}4!&Z2}cmEZU78mow znrM6aXy>XuH%-S`Kn5`k;NTEKTDl{Zab0wF(Qv|ie5w#aj4Nvxt8@6v#0WkwStpeJ z-RYYlu%DQ>OYOr+UU~v!|BpbaF`0-}L1&g^^tYr;gj!n-tn(zf9(8%)p}X?WR&bE* zwEssBLqnmEA2goUDW^<|{L4WEfZIaQSUu{>Y**Eu2%AXD=v?wflY;Ln*7`OdH=b$=!H`Tn6roBsqf-^1W|L_Re&2Ny^D@mSR++ePuu_+v|XzYsdVTC&VPEa|oo_VhGv`%ei|o;;(M28~N8PsIs{Dir*` z@R|;B-Y1is;Md2IIS>jUZy!Sa(vWaVP1Mkx`z{;D1<~c;h(}rS9U4jeCtUfGDDN6x z?19V$cH@oeUSsBk4RFNNC8E3=oBLwIJMyBTSnmrTnG?VP4gTL%n_Z*Av7hwq4)Sa2 zzX69*mNMd6&EUKr#=%X3UB%RlQ}fhSPSIMjL3>tIY>9G7dN_Bda8PO;?Y@ac%29DM z*KQNwPedD;PA^!)$-T*d?M(**4lpqmy%)u9-ICL}LM5!{H6Iyuots?MO7UJII@fT5 zcRi*>#TrJGg`aKHu4nQ)=PaBxs>b z{XH|Zd}gT!sBbqF1do3dZE>`H)NfzGJe+Ko@rjL3wm_4h1?HIrw$vUnpbV18Ksqt) zv>E;T{)ba&jcAkqr#rek8aIf%eE!Xufg;jr5HRE2@amSb_6cgHfFlH#{uu(b|Gn{f zof>s$+lk4;E}}1ddYRK@3%GJYJ!u^SJny+iGltK3&1^9(QpeJ^Hh& zk8bmxV$2icpETwE6gk0UjJ>Cl9?vU=Vb{Vz1!xbOB02v=;Vr4$yuBpsI68hIA@ zYZE0m)^!3@>@O{p)v!%H4T%ZBXH`nKTp*QC!4pd0aapv3iGjg66!PZe;wl*XeRp`o z0CUBpuoeF=(uC=OM8FW2o9;=+mgMY;QLr&^-Th22a8weiWrhrKF0mJ-ljIx*oH27K z>o>S%CpSFy_G)?CmC7~T_w}+t!<+t8eXLss*FX`qF=Y+ZSW@qkUpT$e{s9jCyMBF4 zQxnDZ;o7^yp@jyuNYc&me1Z-^B<~(eh zNsb1Fj|IVk=`Pmq)vTHv3vIqPm=e9<{$$FH!%_BVMi1zh??X~QntzYmJ63oz&boJ* zCVsjeTssTSDL$Pm=CtAl#0MAs8pRhVHV;GyO3BRF-W|g_0V7AT1lbZ1+KHH-3s}Wj zalJqA08`{3BXuWvG&adt;FU1Wou46umw$jgMff7koL03<^#Mf$UgLUU_YU3}?{GWn zyid7=3Q{^q?FErmdD>H^CiaEY_;sSaD`pVm%kDd+z|bJkfCF9L*4fyEr{4kovSs#w zia*G$l~g>L0i20A!>jnao1tK~^>WOmlo@5Mj2`W_3Cz+3*&S8tRx5;IW)*6;$%i@m ziUziC2*AxV)om5Uk>T5aDN6v2gJIeK6H3P2M2H1ulRyJdY8oL^yrsH@TNAs@jW!{s z&qyhi`C`!b@*p>uvhJ)e(Hc7cWBa)QC1iu%@cL&0qfgHN>%{LGa@LTqYvp>VUcWbx z4U?TzL33WeYT-C8CYqh0c3!~mDv%NYzPIf}7ltd-pmQrEH!=VU)l)rv83grcE{(?L z+qQvTF7m0G3h(dc?xcw-@LQG5rbLsi$)J`!RX?#Gnv%Jv1>4e`c)62 zLprhN+o)|64TH)wO!GJD{*JPI|Ed%C%&9u_f^Gnc-u723|4vsfjqbTXEiTg8spuPP z=)v{9O&kaLd)1bIllqI}jrL>-}|RPHpW9;Qzn`9+99T|bKKzJ zFI4uwylKi9TC5Nx(42Lh$EArkR>trF_-E?i_ECS^@jwk3|(?wv9di4vY<&;;yCzm5LQk;llh+bA~3_!t%DyA#(wAh-X2*|?VJS_)1x^P z^C{}mNIX;8K^Iy$^P*!iz&QGZD$cZFOURjG!ozh|=ez^;`8wmAM*8`OXq|4bp$HZ@ zYyO|oQTo7GF_-`);Qs|f<)|%SuPfO2kvwtlVEC2bi^f+#GPR`oM)2y>4rk`x)CYeI z`HG*ALbX?LU zF12HU!MR0_M)J%>s=+gbld-~JQufkVdIqGpy)$#e_NF}hL733{8 zy>GWWBm^=WixvE*WHti0pR04LeaG>H6BR;{Z%J^_wSR(@R&HWW0E)&HsXpf4O zbWmSuzrjCgw*MNP+bw@lzt62hzL4pky@mt93jZmcY+T*SuaLZ;9Fc(Z1MayUA;#L+ zj~qE0TWE5b=+$}q^L1M>^MtQu;zgqS#a*ZE=3c&neDIKD20iE2*kx_`vIq2(u~i#V z8{nHW07$fQJ&;!jZWEHlZTmY`@k5VeamHSTkNRw|_$V*z?ubzb<%Ole6A_U{2c^!tmc@GVlp2Wf|T@({`kQh1))+9GG_~T>Vdpi;8%&(C$dc_y+z}2+T)`nWGRm%uUUns1T5?a=(J4 z)FZb4dKDqMBTTf=^k_ax=}~_x`ej!%5S>=`9DHkhRoQ*?+VS~IQQ!bny+5=Y{TYM{ zpn!XnU8c9nRwR(lxA$uQp#joy+@yAF0khFcwmnzlYw>e=mJ#sWKACdxA1_81+*aTT z4uzI4V)1eEfQI~>YIr3q2=&**XeCkU+fEbijid# z{%*mD9&2U960m3P9c*@b9~V_=m`-d^3;VZYn+y#TifLB;r|+Yf+G{T^A#en=2# z{ShmI1Ve29)W(5$de`k2n9q3%X^G{I76zt9Db&{buSZ~eQ5hD&W+8{5d{vXl8LA2myabV|v zxh3#Bb&B^^T%Bra-ijNCi$a&S0u`~ec@5WbUZR}}(;J*Q|tML}L?JV08IU{Et z<-A0{13bbdudp7)-FPq`sc{q*M(;2HuakUEi>DJLcVH++1eHczmnVT;G~110&x!6X z7Bls^cC4FFaI5a;^}b?fpIS*>S4RDlr-R-MWLj~73V5%@T&t+OmgaOGLnT(& zgnGZgXp*z4&In%DBGDQ^1&udecqHG4e82$i8)3>VLV(e2eA&1#`EE{_a2~G6mvM;p ze=OF%!4?I=ygzwUp{{iCxKO_JHS0QdR#VKhIr&jSAF)Iu+lX!VQaW^59b=I_L6sak z17lXszHAf#Lulv#>dy;y8_#dvMH3ROY=xMbu+p2)T6fBYc}qi$r%U&QlK~ToZlUBB z8#qkqam}vW(JYN4GERB;fDwp(V+DVGzsUu6{oFijs;Q6D35*HAJ{sk6pxenNuG=eh zX>lDiqqW^L^z+k*dtQ0GEuoL&J8{butU!f+;|SvY{z#+d-?1yyp6zu^o)tsRzF%ip zzq{y@Cq4JPSj~Y8)?o-?eIlS1`qExh;X<5n%fIHNh0FuTSU|$8I#%Rl{JlYsc`YGN z1CDa;8&s?`uD4XAsMzWTmvDLcozH}FD4PR@6nSen)~QM zPtE7(xH^ntfv-zeCE?o9r%&!~2oiZ5#)sbKxT|JP2vgT#4;w&9mH z7(%R1w35<@9s{2d7gl>!3mUEZ8ij$j0#ouPeF~}O;&z?8g~Y!JxOZq=y&+R}nc0Nn zfmo?LfqGtlXM&6ujBR5Y=s42f&>)F{L@*}N)|`e17aMa2HyZ->!}nSiW@SM!GvXP7 z-AF`xrS@Tq|5Hi-b(P|z)HUDqmfoCRf1g&gS`iQ;@qbff%}Rr2 zKIy0UnTtk~oily()1bjc1!KrguV9yR`~OpV!?;b#!LF$*tUY>P3BYW@tG};ifU0Rt z1r#V$nPPCqnU;SunAkjVgSI|6HbsZ7x4&D`k|*2);$1?-ltziIB~QFgnI(sY>UULL zcfxnj64zgUlye*Qc>^}4zy9EVO4q=@Q*5Nm(+vDj`WpT8)|`xKtijC; z5%k_};8~*)*YlrJ1t}Cf)ylUuaB4wfZ_Ko>OmWLv1C;klc5~*Eu27XCBhs;o)8OFX z2RmfvpQ&HTkWL^#g^wTFyn6~}K_}Q0#;RZtwF{hL#U}6E83z96>kMkd(o{duT|XCc zL{(jAo??ym&9zS{M~ELU*evuhTd1IOiAwG{c4j;XnV%2qM9On3)2;0c=NKU8alVGh zUz)ju73GL;7JjnJjZlx~zHID@v>%*583W!&V?66jyWvM zs~5(z^uOUumI2LK=`4CCvn5AVlqn!yeM89qUkV7}Aw#5ReEb|g)8EpBUa8naxL5&Q zXl=!G-%JWU#MhlcGsV6sMzfH>olSBQ2W3fhm3SP?r_&t!z-!IDTpA%j6DhS@g6r}! zPf6(PuZ|O*v(gWx{RvZ!eY~hd1jCuRKgak}Bz_l{sboLlwtpp!CgmA;X%zQgzd7}k z-c@V>0ZikuA?c`ff%lnZX5V%(i%s)oUF=t)Z2r`%i=YD&{ki3}ess;otKny*LMpF%XgH|ZQ z!U8bK;y%e^oKWZmmYj9&t+;7?&`QQ!wNSbk?qAv1d?k5{loL%>3Bf^M`R~7fA7~q< z=?rJ;I8)k8bHcYZnxTCokq#^O!!ci}(&Bf}O={zluvL6JRSZ@)W7SJDm_kk(yGHpQ z7?^3bE{rG?m1TDr&${rjaRh?;V*vz8MFaDSJ{GLG!)C@PO}DlN zJc{|?7l2z@qZHMV#=$tYpC_w>I-U{j3hKOoZ1UlUQ(=H&$~FkuS;ZIxx?F(1?ippN z9&Z2hQVoNQoC9rLlyA~E;9Yu>{7VoN&Cs~~&pJD4D0t)CI5qR1h96PD^PV2aQoS}k zvow7ftm>{t0lTSDYn|MkhlaKdVbT26S*dmj8ZoQ|5+Vf&3vSJ>DCvmE1?DV>lG^a` zz@nYBsWs7>D3aJxZUjgf8ebM_dEazV+MQzs4v$d}G2=!$NE6w%P%q^w=jxMI0ap_P zR(9(KVb|2S{P7PM&koSqwP!gi?gbKoihB8bGtL*_bQFCpl zVbS3y){v~3kJnRCORzAjV>MT&?G6;TWLYO^uCQPbs+AZ*VO5iNH3^Rgk1X1GQBqhi z0#Kv#fUe+NT+D+3N41kn0)K`85*NhE;} zkNS8i4?7)VJZwgj7t}}TwN^Av*?m;b$G1~3Kyy=^AH2zXpz*JF7;VZEPulzkkX!() zgury9Gt^{}B3df>6>*yY{gnmeezXbnMGNs`os?aogMG&Du*PsZD3>bj2REHAC?EY% zznh6_boeOkx=EB)+)3R*kNbqr&%I~Rb8z5`GaPQ(OIvd8ZNhS=qyWq0K=-4e+>(`M zDIrO7wGR@Y$puE-RtoFOu=eviXO$lZQUe15?hCkMCemRu0}C@Rmc<85iKTD)izf`e z`A#$7949pXAt5M!zEoC0hIU?>;knob@W}Z1s`bqa!SMx|!?iq@ZTTNLqVWHe&Mc|H zJQY9Lq|4~IuH7YsG>Hr zMw|Dm@MN`}VGAHmmODkF0nnFLu`sgm`@2ZBN7&84nk&D`nYZ>8#A=JH_uHNhxc{T$ zYW%q5P)z0?`B>gk;|S%^SrKKlXC~!kp`~OzyiJga=Qyl`9KRUyU<)GY;r;5&JDifd zIXrL!ossh1kki8bBb%7CZwcH*(V)0;Y+??4#TxU({Yh^^C_A!Z2lvpQb=vo&&STqa zNMP8?Q%(Er73mB0cNbA!6tBT|Wgp@VI7;Ga>o>UJ$nunKPXY1``-Nw2P|*ExXaYSB zGuTcG)z=Vgx89t4R$sC3HO}ClSkw|InADXe-_IW>(rW==z2`%i@KqG{1X@{xD zm6V^G(jG9wfRASxaFjU_Ouh?FnuuLf89JYatqTVJ*o$!tqhdYz+2Kr}Kxq_ks9>s0 za<%npTJ|t1{f8L#YlCXmv0Mw#22+S8ptMBoQjIB$+E#pZ_JT71f#8DK-o#K@S-m3T-!5thUw51 z0iQNSr{W4%5_o_<83bbDbu+*EiZUy>e?IA3U5u#s5|lfPI0JeaJdXYM#H(z-F{ncv z;g+4Z3zQ7$LrWPdR*Ey^dQ!|6p>FO+;Stt&;7XCt@FHCZC{0n3zN|5d-tlS0rThEN zJcF0#lQ@c>>oOSgB)w~6^>s3uxm0)77f2x+wVG3bOKB-+q^Qu`?Ae`eZ>iXjn-&L+ zjpz%XrZa)$M_*9WhJRZBo%K*a{l?0`pO0cy)`jS*Zy@0_aECr<|~x zFcv-)$5Zs>pLw5)-4`;gMZGjOk^qM$(WCSxpgTz7%~@- z54uRm45nbP?F=e*y81hQcZh4`?Uk?MjE?9xwETkvA)3pNZ*GifdOI!};dU2f8*(yB zioR&>l(~{UKOx067x;2xYus3l(GQmiaY=R{Oa+$3#ya+WqenuUOEjipYvAeb$ z&Dg@sid_b#DT{O~`FC;_JNbTiiL-eBT#Be(5}=l|{RSS81bMP(^!1*g3Lmz-(e>)S z>)5OqEocC+_UKyYW%A4yy-%plXIK(6ly|A}s~; zXWaSlmBztp${bcI6hd>WXUfL3n_8MDZrs;K6rl%t?t@^mHyCKG^5d}5cB;xkfi+x! z9{oT&^NK#nT{Y6&ZMhijOUX!>`Fd)g!T4EKs+8DqN=-ct-?q>Xy2)^lVBDcSV0{|G-KTZh?5ZH_)py&w>S;?$)8IVf{!Lz#PXZjK z&iRknNmkbUz;Sp#b_SUVUjswV->S?1rasP9S8ISV8j4PePj~aUfdT9FVp-(_OalFs zP)m;+e8RQV6y@ZhH_|N6T*a1u`T6c0^TlmgS$LR_$&tVuj+7S_n%mIQI$`lY$0b2| z6q~3~(s-09P7EaJP8bW&q*=G$U5T)^MA5PGn0$3&WEf3wv!8wy2lNGD^6LL}?@I6^5j|x}qEZ&_Qr<|Nmb=~9J2y80E zTn_Z&!Q0cWNi_9*ag*&*ofUY|_XONFvdvqySJzhx{oUK8rut;^AQ<#;7kNgvuED2$ zzl3iH`qdlp^~~i(4qiwiUj6WOe?|A>E29;BIY+Bg1V9y|4dJ55ox32g__v!KYk0cj z;|N|CE%XZZk87xG26oHTRo_D9yko<;&(R$ghm#gIK)NZnn}0&{=u(L zR)1TlR*tzF>SMfl4~&=0;oIHj;HM>-pf87~&Q>nu9S^Bus=lBR`cuZyK)+7_6RgkX z`~7k!x(0)8KX4)DUsa{N{|q2Tnha^=51WQjYDT$#XO}i%5rnb-=L95q#!l=*DU6^*hYPfSXN6b`|SAILg*=u1}cksOhHa$f+FAZHi+9GF?b zn|`p1AwZ~h>V1F}Lp&#$LyiIXobbP_SgrOZ0ysfjYMH7B3~h8Rv_)h5sGI)g1dyKz zO71)8qYu}!*znZnB%?|7o9{YGKwbwL+W`|%H~ujvnVsrm08P<(6^k2+fwrg<iI6Wy$9Q#QPOg8a%j*i5^|d=u};sal9$+PqKkJSpFXQ*%+2>S7-JN)j)D zz`#mamsrd{=&vqK*Vt;gQvO!{DYyh(O+N$32sRvB-JQ&ak2 zQP$jJnyFUq97f*+%J$lL|RO$H|*Ef45M^k|@F|f0=eCKg8((t!xT4<~b zxkfNHKA;YNURy+yFYTSDv(@iA5Z8t>K81~P!flmd=r4_gv`|;$RcZLPhJ3a-OGFL z)6BjGCk!M{TE{}oxVRm?3G2_>Ve^wo1MpdsahbgVe;;g9Jn1N7WyIV>yXAr)V@bw1 zx5++hS7$$u3z%ut;z?BNePESlxu%+@*aU566#|}jWtr4_9#4o0M0tC@|N4hL1i0gZ zm6zeJZsIF{=ut?88-Wiw3Ibrj`k6`+|C#>ZNrkM=IRXnQUtmz%PQ2(tVqJkdRdeEG z;QQs5S@CtO)tlhgC##MD5iTQ5Z%E$up0dln&h2}?ch7?>IXR01{mhhG}iKjIB{vtn{?L1!$~LCA04)mLBO$G zS$Xq*Jsr?UmExRIuBSs)e35653Yb#lrm29c3=cjw);V$X%}Gj%u43QeyhuFHx&}U| zA9`}*95(LhC zQ+xT#t){%ig=!_Vpf#QXMWNpORrlR~6_OZJDXo-qNmmm}T%I0zV*V_Fm*Wi%PQ=}B z4;7@IWxlZbg%fRHwuF?$25+qY0Omcdsf)|DvSw)D6bk`S3)@4Tm%#EvG1$gy7rI9n zH!}!*K}fl>(Bc+AG@$!2@lC5l{A?fjMNMkMrpD3)K7{LhcpykjJ29_T8kV+> zo^@7#-H|$e+O;wMZIFD`M@{3_54@Xh_D+^0 z`s(->12+R73{npyvq&tv>xak$z7{)G?KIvDz&5*qr@dRyVfZ_6?O z3sThxV~a>pr*Gt+*A~W}HaNC|qRlhk`lfmOaztpkQ zXoo==!q-Txci8!VA?Xc&G`p|H|kFF{sGUP zReZ93o6yL@KVyCiV8U}NNg%H#4=FBqaI*{kzXeaQt>OwM5bYgA@TZHP_=iWFc8P-x z><>jmt%#ON`*#AihR74TR}ztgPcEEG3jBA-XKi(?+@(uiZKjOgM zrTg?{30zi*auHHQ_4*p0)*Ks`Cuc{$(7ARKVhfZc$aYK?kW;1&t{VH6L;v__gA|2K z`&#)-1{{Qw%q(^J#LN4MgU0xAFmA2h zZ?+l)_Jj?ki$XbQQW8Al^Q{NTc-nb?3eh;8C&LwdkR;x<8Nk&G#h!`*Rs2LU_q^K9 z>Iq{`^_l15>sciELgEP6BHSQGz`)uaww+yS+p8x4!y~n6i#hN$bylxj@cIraUue{B zA$HbHOm*KN`hzh4%YRDW)KIC5)wCriuq0U-#`fGM{trnNq*VbTj?a~uo}6K9+FMH( z7@fUgFMTWpQht11I89fT>LH1!S>4}+?>KiU4QOw;7N;-=@BY0H&#pAgLeB%TMrU>W zm*^Wefv2Cl=JY;M%7=g96+Dq|#_5lbekOs(c!g<((QE_s57(!I;&_lJUGVE4RP_WL zK;^3!CR8wq-g=Wx+`T>Z#w4ZVAm)9j!ZM<~QH4~jrxSNE+ zXYVoiGY1TkYz0`uAoa}Tu3Bu@Y2F@NA@Oy?i5&tPsudF`R{p;^VUbN8b z-k_d6d&l_+`GU`^0d;rd`jwm%NZbM6hOf7_wsV1s-HIQlyadv3^|Gz`6fRXYM?+pra~}WZ)O#FwPCV$1l_bV+ zqXp~Z^*AvMJeTsmGtEDoxmuwE=iWMmQ_AlVOX65XQx&xzyx5@qP){xoR0jZ0qR*)4hKvs?~SdX zCeln9(%f*dDrpp)Za|n*MK`;syi+Gl*MHT#$b%?YCqv)&OXw&T-FI^P@NepxFXAy7 zWP#lcd@>^W*^$lA7a;!nKaQ?EF3IeB+e|f6O*Lielw*D;HOqB!owBseEi=so6?7a(v7%kE2eL!$~}g#jTDm=(BM zry*5QTGyh?yE5wS_!(aIy&yjT;$Efgy6P((1^(XTL7aWa$R)sf27VKgA?V?<$#e0z z=lhQVE}0JIKb4#3f?5_1o#*x*ft_a@$_2tctP+6BB@UB#$jm4fX0#eQj0DflE+GI+#hv z;g>Bh4akC~u$MpBD`uL#q>QmmtL(yI5L;8{Gwlcx+Q^)w-O+)^7lRd~gdFp+{H`H9 zK|6qf>&ZT#0QvMQBKRI89`=jcsGBNCC88lfg2aZdy<~u5+@B8dZhhLph$#-u!-0L? z!!Wj8cx&cs&#_w_EadJyrzJ@BE5IpGIYySw+XdK5&~@P@^Xu8@I5l{d%u>(!q;M7jJsW+%=E`9Q-gW#z0*^5TDaa1p=Cw^<1Pp_9V?Kt}%j+ z=@rCO7Ly&z%2^#bkC}>DFU-cC`CaCT{Y#}+IbHGdwn1#L)JhwW&6{660+h;hmoIlq zS}7Zsnm5U^5NeK2I@OqLfvLx1*ACtieL#h;xw8R!#@AI`=5++C1 zDSJK0?a!!8K{6%K24}X}N4#tKCzQdiCG^?kh%M@mg3Wx_*nT$5*dS-bqRWroN~Yi1 zY?Ged*H!)`=27ZA{$bcD5R+$yFg{t6_l_#3BSjFzI#pO9#XV7mjh`jSZG33>DLRIvDhzT$g)<`@-^Ly{o(n=`I#RTmWqan+>Y82!B_ z0OyhZ|IUD}ONgs87bv##4POxw;3}4>tsm3)P{IA0@++|F$rq*lp}~dxM&p+f9du8S6gHPLSz95cHRc zH(d@xB#ZVaIvku$6`kfJp9ZUHkk%SsrIrQj{BBnL0$||rEYs)taq;P3&t{jw3!8u3 z&cd{ipj&OoM>+ref*_P+F2Z4M#(yYRXxu9H^)9osbjCwubU8ELv#uKq7-R1kydSy! zCAF5rV8a3k&mt;*zR1BRfxpA42*#LLrsG>!2iQdqlZ4strDGvMOyPLKG}f%k#N{r(}?Qn!`Vs0b_L_*l&X z$2b*-Wwm>v)&KoSPh2TMRoc;-oK?YqmkeyBhM`>4Sp2}^h7?1b_G4@;c*4mg;FLKe zE9%m37yi&4Q{rou)f@<{=VHYNy2;_X;p9m}Q|8PmLrX`R3+l@fa91Jd6+3)5q=s8n zyNaz75ktW-N<^x-HI)3mA{J6fXekz7AjcB*s;-xxao`Uiasxs@dtW51BrLq$WwzH^ z!jv0$#iP19V#j!AfZ$X-jg&`1zhI4QVgo zlJxVWf(^C(4nmDARAr}4!i<+x&7kkEF@wfZjU5c7j~*LPeQ5C{2qc_*+lG}UZ)mX( zFjTI{$!B*%UWRqLQBS>43g*E~kEjZkhtUhpVG@K?s{s>xM*x+5S4~T)aK^0P+-lZn zJsy&01aH zOu_-h!YtSwD|8cQqyO@YxgIz!*XUBWsf^^_Rk(2Cp;ZnQN7RgbHFN}&nQ12TJ*#Ba z{>d{4sLvR+u?yYPr4WOGsdKOb;i1Sk>yh(~aN6Yh?@npK zMkQDw-6s?LIXF&v#uc)RdMu8a;8oYmshZK4%2g}=hMN7&iube=zPl(fLo?7Oj`|vB zMdZgfhbYdE!gG(vbO|L*%vHGY%BIRsa3qjz@bJz#{J-V<#8xv-tL&N}+KFhl2->%R zXMYWI5Q*~&3%*ruuWI(63OWB^(U?-)>q_8z4~5gZEByNVIeuui#+Xue^c_bz%Jgbo zcr@uW`(YxRkEDJv&0^VoHUU~8$H=TV4^ksvV4_hkd=1eMKaK>txl#TYiuqStpbl|2$%x;e|C?GP~Hvk3$18(`TD(issvIWl2so6wbD0 zLuIY#SRN3kMy#;%Vrp+Ej#xgK%Q*piFSBkkehEhdEq=Uw7n||`1+})BM_+nh zmOY;1W-0{0OmBIAg1z>2hp1elZ%2=6PkvQe)q81Lc_*a7>a38i2P*c<=WoRa1aUc9tFU@JSJrL7E zRy8-Xmj8fq-xIbF*In^+4u_Q;gpdzTX03xkoSW^FlDPpp zqDY#TzBHPMiD4o(W9cYtE@vVO!GKUnd> zPaGbOYO_gH(4c8F8N>S7I3%+wak5|U1;X61wITT?I+dA$Ie~9`IhLdRj_mt@ND7S& zPicR%ep~yNkw-@|9m7?cDz=kdKj+?9g|clP+Dr5MKTdT+!EWybX`GxD>AKCt$g}rG zomI&m@$oY6+WmIxK9C$FXz)|-Ie+zzKM|~%wm6rFg+_V#5vd|6;3YD+P!f%2@L_^r zsIYsp^rtTg#W`S533iDMI7aPZ`K|4#6Q480j=6$l0X9E)(;~6~92W&4b!5tsRfj(E zg4P}iN59wm1UxsgKyXbnHgSJRBi(+yYsPu)_UTfr6s0@f*uj5G6NyMIcF9c&C)>RB z1do^-(reg-6i~}Hpuw-Dj_Oo}ES(=b!z)+^9s@7@S~&+9V_-Lca9z`D#b{}Fi3vCP zoaN=N!;b#vYF&w#5(XZS0G0pnOaEm;V7@m zEJjli#Jd7TECm^At~D5ryw+orwdQu<%776e@%cKSj+-$cR+hxfBk zMiW_9qAdU9pb@2MZZ>%X?@G&uUe&j*F(yBQ@@d6`3Jzr&U$tiYz*-oA7#MlLi=V>^9qkYO6?2Ocr4qG#p@M~2-Tv)Qr>s9;6 z(Y}Hu)8m6#b6KKi)2&OLf~JO}53AulJ-r4tG4*IAxYAL9wUNAcrYGBnDt!4J$&$}G zK^g!9Cb=lp^&g3kxP;nM-X%h~A;f|irICTCDqQXy7;G_hZE1Lv<|fxh-iFwHwh2*x zf?Ge?z9-72`F|99&k(WcjmO}uwew~3#eUWuht;StC5-#~-LgE6X8^QCi+L5{sv1hh zeHY_ugTh=M0u=OVB<>P56_laaT0irn+39JdF%lDlsv zU&@$AO#FSzPI-@Vi07h78!LocLdOR&s4nHVs>QV*h2bc)hoM^jLAdd(Es*DjVCe41 z(eCJ5stUp{``Qy8FZK-oj6~+7kuQWr---whdcx6sPYe8uFSL$zg}V&{DgN5{5OTMK+oksI@q&?)^?gqLPB6!}~9H8(6U*$&ujX#YLa>^`Bd@Y#5lKDmd|E z@=FF6L%-VS%cfUkL)sTi_#n7`M=JPq>H%}|huil=<3u<>xwCOr4TZM@k|RZaOiAUg zeP%6L8BV_#0>3nCCbU+E78auWc#6qk1r^ zIsKs52F^3R`&3`KSv5b#C+=E6iV(4%)8wZ7I5a~T%sTyIj*_@)pa5yHw|cF~PuViv z#-uWY6j{qj19FJt7jB^+&1l@!oPmym_#8ikl9TQ}j2ZD`m~?V4oJe8m=5O{yV1--Z zNuLr|tneF$=ksdyn=d|r{nFU=9zKhNtK|pZP#YZ>^NAhOCCv0Y?lr*3YHC1zi)3OV zl1F^%~4!{bkVMrw&Y!P%atU~59zX6-{xM2;>89ZRO(CnIf5j2Jf$W7 z1KS|L0kj1=hD}OO)RR@wVusuk&WB$BC2A{wg3Y0BDs-v5A4S#!Y5ar{p+}eQ)s=Oj z!RB<5@w=h}k9fZ5$NV@X>km;eSN7Ume@O^a$v>zwKA_cND(jiOq>Tm31djy{8FVMzMf;eDAWk1cd9 zkv@E1BY&`4>)m^5t$?e#nbT~kEVRcEdvut26?6qIl^eNFxF&}UJ#xC={*G;)yCpd%d z-xodaT0MpKV|2M?NOdt8TWLB$<{fzUqd@TS<&?i1-h zKN-tta$(_EACCyn=wu4LY6NXZ_fAzI&IvKr)0X+<(mP{5o}g<)ow1 z^!S7{yPEP>1%mlB zlSr#H=?tf`aajNUh($VnEJzvwq6KUqbB43Bo%AiSep_Wg+>dAt1*7ep#4AOBZ*xOT>T!T6>hR2i#C#ap@=X351}bH+g3`jIpZIqE7Wf zpFbw7W;d#OBi{Zb0t2jPUj`VujunIa<<3X+>M4DtjU#(c;zYTEMAZbN3$CR$5lVq| zpF!Ux^yZH!s;sJbfGtoayBPLi6FlCU7%`V7$KKC;vI@kDaqPdN4y+NZP#r)P{Dbp> zaNw=C7r19T(MRh5v0gF4f2xjPbF4@c~uXa7@$+?pPS>NZ%7?F2J-LC=OrL@VufZ1wVQSY}Rv61#s+iKfw3O zRu(w|eoLmzc=-4mz&GYEjw0Hv0UUO~^qW4@SqZR7j#8+7)3!FnRi`M2pRQA^U6I+B^8us_PsWQ(?Rc=A+fejWK+Us0Ivx*x>P$crw=e8Gr9!@X zK&3OiWO^GYw5rIzqfb{V5tAH`rtE~wFb{LM!Sc}&@Yy`gfA$&To0`NeCqR+jcvYJI z4P6oQ!P@i24c;3ly+GL&{mG{K!&VZ8(k|PC`xElkLxtviWYd;>8)d$CDt;QcE-XO_~%YtZe$x4Fp*P+8lyn7KDr8EF*(SmU-)86 zn?vNM zdh@w183eJ2p*{U-;ctfk2%TO==d-^+82pB0cOR;I4+?Iug`dO&o_8eg689{~Xd&Aa zlZg6W$}RL0KxWr;%TXpM5$mw5IxYN5M|P<+(iWES`bH*tTg#xJhg@KYxZ+jZCibfuCZ9NIG*rLnU zYCZ7|-!zpqMwMO#+=C@ky1QlSP=|oQMgEa_C*5Xqd_h?Ru2AR=aaqh2bNcG!e4z zCSV)K2O=UWTdHd^<$W58yq?E);%xFS(XQsgpHOSV7r84UluT1m5eRx>YSjyqQ!yI3 zCJ)Q!Pi#kJ7}rYu7;G8EfA!Cw*4u+0Mr~x6=B7_30pczs=N7*0Tu~_OI63d=h)zpV z0q%JX!%oJefMzH=K7wO8kWC;_dgZV8Wgja>h^>2Akt36aVgqO07cQ@rRfj$rCnl+|iUHpkynU~!rOUf92Rvd<*a|zzM?f!W9$14y{M~+-dwf8Xc@AqONb(12 zGi~QCBG}#Wr<-0ri19+tnGAt>(yxqfyH8E>PHOk%d;6#7D1A2hQt@I~N~?7RJSSZ+ ztcFj1pK}xciZ}x%i5sUWOB5ni@u#vIpHvE{LL2IQqH^o-mc+?{%LKK(wXPV&r>XmZ z?={Xr!V|PFkG0;W)K(Z$a;BwT3UQu1}Gsp5962M zLQGCyCJ?B)1CD0B_WjR2y+>cv-cR%!vM|7ZHf$j~PY_-6!&_3mnVWE{%+0_tj`l)% zDF+5$q#6}^?`wCObO-{huE%L#)#x(Bdi=6J*FGoC{V|brF_u^Qh>v3? z^w^2ZIPT7c51-uBQeD#mI32lKX;2^^-~7SfFyA z*ADpc-=nr=-5d<`#OT9^Gq{QC-4IZewb3!kzprF)HFEN2=ByM8bbV0Dw^u`1lwI$9 zI~b-CswQNU8L$QXdQoIe*1*9u;iR3{ZtX0M3L%bKvjZ<;(I2 zIZ$0;dOv)<1SZogWVtl+MiNk$gWMcMjY(3j=%16&P~#wDf;oNVFf8+WI>Y3LFZT6= z739CMS{Hq^$1)2h)0M)@Y|XACt+y7XiNT0gR?4i)uN$}P4l*9bnN^ZLa5W!7jxD|g z_5vZl+QZ=-FaEDDTvqYF@)gOR3lX>WetTbp#pehTdMHM?{@Q}(Jq%vpIK?QoiAW4c zyk@%81P|G_HN#C)9AyNAkLl4aKV>xidE-0~q$i4o7b-9Jy;=<7NU+1M7Q|nk9{d|f z?tb{5m49~ZJV#T2YJ)2XQGY$iEFj_}Ib}b;4`Acu1rTUe;-JNEcQU7erumwRnN4Kv zMj9|!;I7bQ79&0MBaZd$60s&u`L_pUI$h}KLz)M>&=6y5fiJ9n0$;>$ASJcY}>1EU2BO-)i`@LS{ncr_7n1C?G${Tp5 z13*1`hdKm%I3~!CylNsGekZ%qIcDTEJ5%_B#i@V7%dJBn9xjeY=*z=F*3vv$=AodWHNZG*EaAxlC`?^zGC{^hk@*IdZHiYKn^i5?NH)7 zrEz}^*nlb!#NG$QzPs`@gjDeV6e0nb1qxAi4jT{Fqo35RCaxU}z-$0H9=M0I9`9S! z4&}#2Q{~+&X&!l3TR{s`QP%`A{4O8ZoqE@z5uHEqyXaFQ3i+eRZb?0m3!QFZ=|J*b zZI!GntWx=lAGGYDcQZGQHr51BT%3hx%-uPwiSN?{R?08 z`Nk^7?PYPA_;UDIO@+Xb?gnTpBc8~tpjN04->Iqf5v|w2&y)awVv>niHdF0bveEGF zV0`k37e`4wd3Bv8gKzpcJo>5?IjQS>bEpC*&3Ck4wc|m(z;*-bbHmw^U8{@-LKe-? zETKfQpd8^6;mU8-jiL3vMkR}c*b?dt#&QyinHXn)#`Bhn|5W_v*RkE(+Vgh5MN0`b z4}yXE3PwSw9=}jm6~aH;au*bS8J&?pb65ikQ^_7Um(Arl)$Obm_G;yq(J>ON*pCS< z9h{{M)4Hq1$3W6xZm4Tg%Mgcid?LN))87qo=0;9j@=~6us3!n|d!vB}mK1L{DO(74 zEOAgvj7}EDf$qfTI0&$d;Ay1x3o9CyFSdk%w4dyz#{#XEHi|7m9$V*Y+`}uqwvnv| zl`^Ie^;gIk;MclHyJQzS4!Jm><9A1x%#1I-2e?}{CYPxEZa4>V;6WzJlq273aJHHb zb-8a31bcvRB%Xd&F%;}OY;3`A(&XYUkN384(Zawc;FDsLzVIxq^RPOt^@avp-MD7p zdqk(n2xck?Jb0X-sPPzC=6OaEoa_x2@Th{|YmMVk{%xQZ^u6E||b1R&vpQkJRdq_8^7;ffkWgZ+xH zqF6nJ(Mk`rmy#T&CcXZt`yTcufZHziR0%Gqo@&I$Y_iC^2!$Wzp+#LQ@C|>bBaYnt z1Ldb`!kG$z*XEwP)42YyF-fc(sAft_q(T;yB@AFuZ*X71^&x0H(ICrNboyBtO5;cO47Ra-Vg~P zrIR>N*+Xv8?DccL@p2b{+i9TpP_^cED0E+Y_adsWpa<$~+GMIfgP0sIFk@+%zJn&} zwsq#GN2o2jHu!uV&I|(`w=~aldb8^n38;4^hhLIA8cgO2(>#*KMlsw?VU@xW|1YP` z)D{SQ=JStazY(KlAqVw985o*{mmMmb+1WnO3B7!prS0AoQBinte2<9Ii@4n&hPJ`ag+>P(T^guIvmx4xB0n;f5;bOG6fVeg zXJJt2z2h<$KX?p6)Uv5)`yDL4NEJ5Fp?zRX*%`O(ExSQ3PAHEdf%D0xq*RB*&J^iV zzdaiA_sQ|^Mj@%IAbQ~hT(==PWXh+`|KhS$aSO7#y3tn`6f|5YY$(lhnO7)6opxUx zm|0w@MOo?S%iyD%o6c;&F3mIZ&2kMiqV40QnmTH*gEY~PZ%B!P!RD4r_wz!5mxMV6 zLpd`4GYUjUYzxIT<}kG-v$NXoOU3|g7UGG>k?}$3Xc&RyXOchh2ewAIsSPR?jSmc( z0kIxQJm^3Dq})%fDxTZN>;0|ug(p!`rN;J!8JbEUSSmo<$hV31OC6`8^Mp@Ls+9D_ z*t)!W#zR3A*uY_Kt}UZzEuo2cKGJgNB_e2jrFzArxMcaHjOd_&M_%#$J%X zK)_tX6T#3*MR&}^!oiG5$wjAPz}14%`oT&RS_XC3`JRWl{84v!SkaBM(E&2hIpC*} z+rzpitA2}%bG_mm9Xcs3_G*!V%6>r)(z3i>+~{&EBpo(>mL4w)DdSlwM#4p4B~nK$ z3zBWS$mPXR-5v#OJ7V7E=bU%9k&(H5Fs9CQIV)mD{fSW>fnqBTR&y6m2wA)N{t94kc5Ti_pGo5Kz| zm)ne;+uLiQSsZ|0r^eH(hTgo2b(j3MKfCRKeCSUmA&Zb>QieoNi{ArY|YyhS!#JksKZ=5 zkXYa3r`;N9xzA0mDd`Wf#n4TApamWG8;3`SPwP~D;$Jz$W}6z`ioqESf-)Dr0azHf zaTk^yA1C*g`E)9u&<{IN?b9SQYhG0pKZ(G6(x1U|Jwrz!Ob`aBWFRGhAXIa2FSyI% zSG*5gOvg4lhCFQql58aUW|)%v?UFV9F*;9uqLcS;4?m7MHdCjxSs8A@0Bm0Np7JC4 zx1_;?S|fvgID8X%<>UO}ql}R2AU*RB1#g+xKm68eC1C}#+nZ$LP%^T9at78*_r)7EEV)~Rwz>gYXwob9s$qyxKdWf71N1VFEB zG{-!Yq{gI;wa#!=$2$7%Gw3Vr19EJGNw%L|xJUm&;|wI=_H)n?2r>6}80tD4_)&m4 zX?=7gP>LVpcqaC*Z2y$BAJiHSo2Si#57U%)2fR%EQqIcXl~N!xwvq;j4|%GR zB72hQlB*bU*0TD`a<*k@?2PQBD*Bx?2P310nO?~BNd;Y@+)B&VMKTrAyuw%(4y*OJ z94;cw;m{r~y+@;@P^;Tu&C(!$K-kCsgx_~W5PR^T=MCz-LnXKGeG5ue`k?g?x$$F= zMx`)Fk-Bzez;p(*es@>|wZ6!7eFX3Nqiy#~Ny8#X*+X`W*6J@DbUFO5@o+7F+z@3a z#A`6!*<-wzWTG=zLXB+3TlhE36UrHN4Qitlg^RBr*xx8rE?91vzm>9kJoSxXjF-Q> zhhcf-oeVPToNc}$8iPrgaeLEEKb1Cw(#*Q|pNgR~KEr_^rVs7XlgH`eWTbq)A2{D| zkt#;fhACEo5&N$cjOSVF163>6S~rVbTSu0fF7@@adjNepA;eVgw?NzA9zGWt&-1*M zIO*CgH$DO`hOUrZ*|3!n-pAwrdpxV5R*P^&Bw>>DR;teOT zJ1S6V+QQP!`T6+mDa}c{=v=E8g}EngG&eP8T^8#<<;MkaIn~al+a~R|jL+>6{%azD zkz00?9<77=zIv@a!?Z?^p1Q;D2BrXsb_Y0h;ZAz^M5b!aMdgage5y;YCHqJcXTzry z)3%A_WjbH){n<%QMYM8=1o%So!Ccp}mlQvSnUu4_=K+UEFX281oPiZz>;FWqIPR%C6$_8$kDM+}sXD{6fErkdo2vu>(4=P;tr?xFbF)C0WXfa51RwUHzY zED`?fy#JSft~R95i={~8dUL~n!0p20pOtqp&HH+ergI-IJISgKnvL(*P_Q-Mqfb{s z7|Ao0V>h|469CocJ3Y>!hJC+zDNS=kEI}juK1S!--RB9coJf$iwO8MJtNPQ_Or`ue z=a%+nuT-UJB+|&(!1o+Ow8*1ZrPnO5_5mqDq(7T&mN%y_vw@YYT*G=cno3}IOr5Q} z?^570y1~i1RQG**fVZ%b3*>Zt_OY3x%BZ!6eZSHzRlJGb=H@@p{#FR={aC7h+Tgdw zxdD_VbN>@30bG#{Ew?x>H}P?lZCQfiZd>442+`6VF(roG7u^e84R( z$?OSw9m(Kw&Z=_w&byXCOI5~?O}XH%ky?IH`V1eFoAUGA@_WtrMtupkfe@aJd4f3& za#Q!M9^nfIuJjJg!0e^Ot&Nbf)e%n5VYrEq7u4zVgM24(-Dkp3H^x!9V%;~avOa8j z^I@;Xo@ocT-C5u1_hqtwQ1OlxpYngABR^u9Q~lW@4OqcPxZ! zpV{qBB~i6omRc?+4uo4Zu1G4cj4k zL>BF95hml7ov*AGUt3K9YiwozQ=%iFi9?aLUB-j5Y#9SMMxV1MrJO&Rj>l;l#M7x0 zm1&DBaOq7qpFrioeH=lxEBbNsZ#du%Y;2_&mGUWlHG!X1dB8b{!s*ur&sg#>;`&=; z+Ik3qe=9-<&-XKki!n7?SLDw?@au4~yV+469fv12Qnytz(VJoH>Y17z(AC3_WzLZJ z!7Ncx=r(%)W4^f*Xo*#mj*O#vJ1GyBgq*YcE`J1FxOvbevl!uV&e^9sE*raO=T|Yb zB_D@IR=oMsng|T@tlD&_W;ohS8+Xg{)Fg8%>DT@Y0nUIV3an(GG|@^0HE$g9BkBZI z*8%jsu$4QCT7NI^YPyGCFNK1vEa95wO`D+KG-PDg)l!;tQVQQd`k0uAGvn`TYrkQx zdfsuJexvdCDxjFL{0Mvi>4}DPS4*b5Xm)R@`7bd~e}IBdy>oIV)bo0#OLO%K2w(}G z1tB!dvj38`J=jbAIh4e4cJ1^8ps2+O@gmdp}vv;Y>})YT=(h^m<7DveqTrEmApu zy>dUdbKC*Mrq34j01k@qNJ!<^YD8N$$)eeRsWEtkq}_h!_dW{;7ZtinedXwx?R-fU zzHyS9-jKF9ys-JSv3FjqHK)+`%I3>g)6Y+#`I73oPZxvrK%aIV(wGu!1!RhK3xr!} z*Y86sq>uRTh{%>VYBqTK70#i5^MEPk@Rpl@p|>VqUg-+eP=4=jo%QLORq?tM`BdGi z#M%rb&9F4?i_eCh@CUqt4WV@i>eD#@{KP(26{cbI#rWuul}S!VigJGVPayiz)q7>7 z4{zltYuc6bJhNA1Z7pjO-2YV9?M|}2{cb)pzJRMOVQx(g@uLgN6Y}k~uFO=#WGv2s z^HmhRV`}0ifVl3xF3Ivb7*x`mgWCdBe`EPh=cn~y&I z4njg8GwgkVer1uTt7Vsb6$(JtJszfw{mj30tN{%<4BkU}3ZJQx&v_;ctcS=hwtYG1 zN0_+1CvnYA=!N8b&tQ6N&J*h>=IxqFxk{jzqLM7s(CQa&?6&TUkLNHpL8bE!+;+?I zn*KgUi?sdO&$|R-X%ZM_b*k?g#*~Z3$19XJS0F$AUh8GYEi|%20`5SSGQe*qsyxQb zEWUxpbX^gMO$5qS_pJ*Se*&b=79>B}PJn1+P&*=~#~5C4z^A&koztzUpM6fPlMSz> z?v>82CLs43;Ri0z6ok`H>w4Q%+yo_ux6g-XM_Aj!XfjV`{X1sgGoz#juhJP~g+&WU zTi>k!!99FQEXz_2zIEMBvF0q}NIOerZ~*~5)}(x$K~m> z)eNya&1-jaxZB3=tJ^S5F24v4r=9purFlWQ<{Q-f&Z5+S^-(r3}%KlJ!H+J7fORq0HXLt_(Y+jcY~+e!EyUe@AQm5ixxae`DLu zw^gnr2;oc{Zm1+h>FXc|P{ujmGS*Y;i};OQ#!l49vkZW`@}u2uy=%7m2u@K%cJA!9 zAVml1tkXv&GrhhEeBW1fW5aR!Slp9K~$+>%|Rv_ab5%q7zrLsiK1f*m!OuqjIAk0|+R3$8F+&6k|f-e2D z1;%GbBBo|{fJ277UxVU^^1$M4qk4YXnZS1Y-ErmnMmr&@dTK7_Ml41JMX*N646tpF}5=^_qabdOrw=7XAdlW>CT_ ztE};{H5O)-uQPNx&NIK7if?kxZA}cIYuvc+Q@L7u6T?u&zdBR~b@KE|a5`xQmTpn8U2wZH9F2{V0ML&KMcsAtmU{qr1MJ1$3V z2)+Pp%+KYm*HcCDdVk0-b=_(uE&xJm1;o2vZ>aU3>M76s#*o)45xLo(zF>G>k!7wt zPA`j@wx+t$k@kmb04S78!!I@+a-2A&rQg9mZGLe%#AyRnS@n|3;01$gGnKWzjLkh- zI*Hh|)t`T4k|>dV zasar5kIfe#30?)~hrPN{bn+3<$LIorwcAPXjmQ10-~>AtR=fn0M_}a%P=2G- z`%!E6L{x5~w=lfyqT7Zhm^|D$BB<-w`%{deR@x)2@`q_YGWcM>!H{CzM9KuWV8|;_|%irkb`k%@UO1?mwZN(vq&en2>K&7)f zX!+TGtL|{&EQT&9-xTtK-b=-59}e-bNxDArc}zlpLs5JYYeRYDc0yKBoXgxK=cPY< zvvrxa$;fOc!R)j`mb(S-GuST>EidRG*xX@#inp)e!ZE44k{@Yr5LimFj2`m+zu4e@L&VZrKR#^H8zGO0;3_oOrtX5NJ}M@41>p*YRs z%7ZWzUowaqRu7{Lrl0Pjxia3=Yv)$CGHFS6gQKzr&|^aw2fY1k!-?#_bavoB6ex*YZ4JB^9C1o(^jLG zG&dm7QjBu`#i$^_3$YFlbKmN6#G!h^`nbXX@rTo6@AwkAys5Lr-l4-yQ#&^i^{Fy@ z(z(p{Z_{3o&H<_^LWax!<=zSTrT6sela|Ln{r(gE2Rj1=`#w1^a}OxOdROC{5*3JJ zKzXo*VenyV&qt=VST}+E4d~$jxf3f}KYHjwgpT9Nr6eFyfX#1oITSDXU1ayBy7!#F z@$fwHl@VWfRM<4q(oFDftrX@G#TZwRBAB`MFi=T$V}Te#sdpeTLKc37m?%_%5C+^c zqE9%|6ihnuxP<~j)90w-B!M8rg&Iw}cU+n;;CW%PGkY~Z_13hyfT)RA>_Dm{)vO_o z`@1ydXs^BrEa@H9Ve8SM0aAxAL?Dn{+)9(cZV0jz!lodk7>OJV3OYKy>#H6*^x@u%~qy^>aX z3LgaW;O?W1nl&#vf8B>y9}O&#xxi_5t@n;{C4WYNc-4-7TuUK$^=K(CNN6n#!hC`71oq1&tFa31nwRJIHLhuZ7Zx@QLdKRV zjw>yMsA`Chbp_5w%ky?GP`R2t8Nh-=Ou=)N15mTQ~7Z` z(&f4MV*-Cs4j6*r_?zq|7v0ElyCrdG9ysOSm4jxlX`qF%?kLXo8h$^w5x>Zg8J|5s zj?!*evh;IcWzkUgpnwFJhuy~_J%52;IF4`$MYx7;4c z8eVa(fetA$E4upz-fXr%N=Em;uZ917Nw!&h6YXC<{Od{2`vpp_e>6fi3nIqUuw%u- zibMB-j3&G2n;|riE)iv60QA7}%=VknP6 zUZ-v8bg<t)@rf)%D~59-*^tWogX)h8AX$+Hg!cKx&V?5$bLC$0{-=0g($ znNboin4+z?e|@)+Jc>COm@nnz0x^0V5XM!mvp4Q3 z`&+(ftgVRDi|TQngwbWRIfjm)5b;< zQ`EkaR%oBlN3uXq;xgmg&LMFtq?!vay|v-ue$if9oZWqts}zk&L%vs+{XEub{4ND6 zaapy1Hq_K4D|^HonsS@_pME|@HJLnq!zq%52I1x<64+Jt;C0k>O-_5QOfR*QO5Z&c z>X^|6Kca5VU6?m=xny< zCpx~pPDuexN@{Mza^u^l1&yyH8DiIY(o3LZIE0;_(_Pm4_x-zBm!UP?AW!T|&j$&N zweBnkNKop~?S}{fw@=$uhh+57)xC`mYAB^p|JWlc5Q#C0ZPj^_w9_Ze z75VF~zp)bCzV`l-o1@4E`)-nSYU*=U3&!%amRjq=Y6INY=rTjn3)OzqzV{V1Z z4fER3Fah8Nx6(%egW1z1oHt^@{|U}XXuSI2YfRLLU$@D>HBao=QUvOjY6xR*-R{<< zqt)36t66WF5lZ<{F#{q|n6>giUR$n@k=(7+@HE20%aoFbPeu!nFH7ZGL%&gCL~9rG zxa~e)lUcYlg&Rkkz8BP*Dj=wX?D(vc+u zVYi@@OpG5{35AXRn*m^R)y?@JcbHu7LsOm$6IhILuH#z3Tf^^(1O&MKs+pJ z4NJD$$3d>gwci#Nd3u7-Ol>eWvovsBJ~ZU9Qj*GpcbnLa0Bk2TsZk-UM9mh-`Bo?Q(u^zkkogw$JDNeqEl|^Ln0KDA1n(QviYrCeAFZtCk%^ z>L<1szoH{6T14C^K45j)qT}xb3j06$Mvm_s{2Gi$c@v?4bz!(!`1C)S_xxi@uCZR! zGBo+F6)H-BeVN8L0YRx3pFyndD|r1AA;y*P?bOTZ`!Nx>NgMzaj1HduPv+0S)dh20 zC=wpd)gr9slrQLsqOu|+iwqmJ_%P)o$!?^1X=b^{J6@C>+BgkF+?6Zg_s!b z)%tc_U;4`#%kugq;iLeW>2fAn+LB;*`CQWQNDSAgd(6v0gwP!Vb&@asRc6b%=Fb95 z$(pW|p%D9^AhFUByv7Dkg=hUXDu6coZ{W>WF~i>O*RmuaZD^aPR@!gBnqm0@nHXD2 zGr3A=R+4U}gM2pVW&Ek}*xTI#f77_x#PF)u{VhZc%g>A0eI0o)zP?QD`Mkckf^fep z1w@1xz~@WZ{#j8sE5SVbe_j+{(YZ#Ddt2{Cxn+J#E-Bn@YbVQLtIn;Q^ zIrp+IIj_dJ1DLEkACUK>1pbDX9oTzo3%t*qJ0lBW;XzeU+YkW+H$5Y+eTzxm^!7S% zr=*i+2mQ$YAZC02zc(PR;U_OlZD(W3r552yT`so7%D$Yt_6vR<7ZIEvWR%hR2br#( zwlV5BCNAz_>E8FmCCO^%x+U`yi^%YN$q!qUUX~1c5%YqM za`X2m>Z-^!z`Ow0bExU7p58GRrmk)gS(^yA7@d*w1yZd?4YzyX^CjPgw3~OWPm36) z#MK^gC>Dsr_SG&NkI$ZbGHshXSCM-pFFT@LIuPuTQ;W{JlrwaKKujcSNrsnKEajxX z4MHj&pahD2KOSYlMfCk4D1a?rKQNGzpKt?1N#wXsCoppuH-6e!d*!HPb9mMV9gFD2WwA5hV6O zaZ+D-2xu`->*dep9EyJ;*&`!6R+q7!cR`gv3$JP!dr^;bs6(`G*|}J&T?<_H*x(6r z?cIjXc@@46#7&*Zv+AtqrqBdfE~MCfgM5O2(-YRLr(3Le;bM20bd^iF)?PST8~NPY zbBav~9|5^4=aKRKD1_3t=2k`?{lk0}8pzKIuGSZT zxQL9gZT}qFu24iDwNnF)}!igH|_qi zTBEI5%H?V6vbs5uD)=Axv_^KeN1obh-e<=DxOYBA7zuKoe5~;Q_9awE<CuQ;bt6o=84XU%&3j92p8V?s3{xdoU z38875N!T8bv~_VJ*Ov&%(A)bBN_QhS<*t#4r|z?J<8MB3_3>g5BW_`u?NLUH2i#>< zQ-q#jo9>8oF!~2T@ms^Jo|(VW75zC83+OSrvsFi%+vdLxq+N0R{$ zrmVVhu;W6z@J1f#>{;s~VCfyO>HGwxVEumEjUUV`#VMtakJF_qR(1M!{<$OlC1!5Y z463WP*#)w*XET&;v$-0ZPUDmg+R2=!l|oIdPq%m7HZ99r|$P87hSN+7Sw&+Y?x(6@{m^?bWp3pvcP z)9w5Jz#%G<(eNDcj>rO`CNdzk+x=WhKIn2Rdnf{Ze^K4(eya~S`;s+G{38Wah|)6* z*HG`9@3*S|osEhB& zzaq7deTsG9^T1g1mG|WI8mUk9X(qm8RH_6hjXv4A`>3te+42wzpZrO0w4-v)isikg&FP+8ix6@YyJ+2IKlsIH&<{0dNU=j1obca9BjN zn~PAn6JE(u9F05!4cXT_yMKwnbk0y;fs&0obxs=-SymHMjo2JM zLXZMV^xGyTPZ;UCS5dG&tqn2mW@@4qmHZ$8R=lP^yDNDrx}2-eR}D-K4W&$3z`$+5$wtHf0`vQSreN*uO@eGCq!GTrwIE8aTM0xmhg+#o5=h z&GF@}lEE^g;s>mXlhj+zLRqkB2>(8D*cBW-N0_9K9sBbG(3-64IWF*?WM74wMiW4F z`-VyNZtsIG%vS$tSy90qMaIr3(Bcc-^KxIT=M;NBs;IYp{Hm&-&pKXNjsILibP~WW57tbJPcLw?Ub|lL)9SAJdQ332C?=rs-yyhoqbRt z!izcwLumjal2n+M&|$*M=%@^nlrtu^Pn9)7{`JN`1JS+lKro`fST~xBbkp z15Y+i0buGTZeN;eYmG(Bm{${}$X)MyPR%!Md+T#Xlv@T@T2JUCYO$!JzTg%=d}6uY z13Y(z@}_NGMIs{BaOnl%C|o+A7OMNQU!GAG-mCYIBFZD1l*Oz87%QwB<^cSq!g zxgaD_%uhvwg|3!503LDd-P5k~IZg(L{$4UeZdSiHprGI81O1yrmXxR6e^xJ#nII|& zm<#H)7>dj8+8?j(fGtgA%B}p#|74sm2WjYaBVqqmIh~biWi(jlj9SimgYY+SkV)RN zhL=-@J0Zf(hND;=uulD|;XW)Ta>?1FC-6TRcT&~q(CRUj2;jl0Q}6`(-QMctRz))F zo6>eLztb^!NHG=>L#e)#pfD%Ox9M|_OHIx9MTSmfVfcOZ+CHjucvEeItr1uJ5L=M$ znFvPC9yQiOv${Xo_F7;ebkYN(b!w6S+Zo60lI|6j?`lxWQ+qH7oF5*}DyECO;{Y(h zjLFKcFDL4R2daO!*7}fPdb>w1Ejz_tQfhSj%xp!D_3#s8J&~bo;EdWuu)Y0+&I{9g z)qJ@|on*TWSxgE{wKqk1cN>%XBtvgxf2mt5T)75O^CwBqj)4nR3aQwA$0w&m3W~e> z7l7Y%@V#zK+Eo|&h-C#}9-VJK8NNi55C%8Tl=VgfZ(2m>_w$JPgO5}wS6s)9fg+xR z?l9FS5yah`hd+OgWGi3;P=|X8I>Fw-%?neSK_I*)ae1c-c)eP>sI0q8Q2T`2CX3p_ z05R*~3`yPy82D~AUpZm8EC;Zvch^CSa7A<(_3;n1Fm?rLllMX!4l<5XzKCI2x0j#W&!s}D!{J}Dmh*KIP~Zky7q6c1%1%SUGa>H z4%q?yZfC_leEFLOn3b1}`oBDLH9#lGvy~#bjsk}|Jnfk2hy_5JFUN-P_aWP6U=Ir% zx0oRajn^7Yn?5!G3l;A!EbQuXab1gS#tGSd*0LkbM5611 zDK}kc6F2rkGq59vqcg0H#oT#SuCZk4f@L8q z+Vy$s)LP7KFG}`pmqZ5mKB<<8WH&&7$)c0&kXb^~*QLK>m|(GrYH2fN#ynD&Y_T};6QIiH@mUWDTb;ZVV5dqc9I3Q3uXdwBxcoP zwjwMZxFJ1w*Ei{qogJKu1_WJj$R_FzZf8MsRlSz2$Z$ln9#)qtnk*L^8D;gI5FM@i zGlrY34oZR#@Eod6UHvYf!6VEe*+9+ZaG zjm5wop$|Gsy1rqblREe%dOvE1_jLC&%=D`Y@G_$-S-Z6Pl=LN_E(e+A&eedAn5d&f z7#$s)N(3~B98weJcl6vicfQ^QjMe)Ov7F9Rcm+zy-}W{;&H@pWNzTI znsy*Y|0Q3<*gpp%B>a)qh)vm-&xcxW$$%mCv8hsB9!H;3(mq)gNz z6E|NFvhOF5RW25!sy)@6+I!=44Fdke-@$( zQ>9TF-^dw0zuy%_qmTv8tL$|QP34|sP&Ak+`sS7J8hlBcNi5+h_~141bw@veN7KoL zTp_!v%xlVlRyzmZA=ee%db_iIZNrdm$sS%G$Mp9TG&d-rWE`eLa(&V@$U-VlcK2)K zyCZBdLeCbb*bw-lT^+zp`*m4KV??!=7FrkzIZS55dsciPO!_Oju5Er!wqE_bCsl~! zIbOGqRIgmW2vUG)ZccgS+q;yAtYKk7-;>12GPMWQAU0rORATPX1`>F+Y!c5Bg!gmobLW;Y4i0 z`UY9=1jhFlZ?PlIIDB%$M5LFBg!hMa$SQwGLoeuq^EqBF6d$#@zorOIT=OJF8^c9J zfoV$#@w0raP-Notm>l!7Xr%5>fNlO8D|L8nN4AhIJBbUVe_Vd8&@?=iEVK}Do21aS zU4tD&*#~}m|D-);ua&^TpNnw<;#fN-T}AevD_!}YA7VaaBR{+~j$g5RApV@!r?!@z z4ahQJ4ZoxCR}>ba=bJc8YwRM{QPr1@UJSG8!%%+k+r_)8Fery(0u7hPv}TP@;Et!o zuu^Y#hZQVzo%nPXf^}Yt_1%!ZLk*rkH=XKIxc?{ahLu?8Nd*5ex`q&f338~uz`PY0 zD-c12{ml8xnJLq}0W)}>O<7SXWou|!PVH8Fs0xP}+ePjkYaWpvy@D{7+fQgA z)rFS|0q?mtkbGEu;ZSF_Rmr8G6Q~L@Qe+D*-)#PG1ux=)&%wIGzH!nl{0D-FLu&+O zKol5l&|T{!$g!eDvyXCk$lb8tacaq0#P)C_0k@4!Sm>%B zK{n>@nMt>a!6VK7UL8uTeX2B;7kz0XxVG7kqptonE%IdrezjRF%q;KB)Ds~Y6d+LZxnP_Z8mfYNK<$`3hiM{^!A&S#<|d9FYGV46?9Il9mXG}>qy7M{ zcPawp#tj|!Ck`fkV$?+BY5Z_^B7`Oae zq4wphb1oDGTC%X(Xc@Tzxisz?$3IO^t`;@$+;QW>lXj5OeOX4;44+kdKA;b zP&#no@4Tj2nsKfIo+eqX1p5m%a6VP*0miN#bg>5&`04rvAVcF(h}H195dwH&rQSnk zs%@EHa5=#?$GP_DwiJv22T}_a{yg=@(8On{X7z)jDDC8}>%OliaY~jTJ7fx6&#JWu zdw(qH1t0!(HOx=iTkV>o3I0vCvO8vBb|r1sPpDjBLwy73^~ZO)Q@&mm|42AA{ei*Q z!)~+AbW~*^dvg7-Y&#lA^HrvRw5JWbo*QvK%^}x{=z1x%BvN*{I}lH%tap3dzG2SQ*HJn86f?o($9aD|vQU&YtO@<*F}KrrB+6uZQ5F-$=YasW zsY3O3kRkI;YLp%Rff<|~c1P+8lo||UjQ7TgPX;|$XjNF22Qf4)$b{_T0I+u$vhwXa zmPh#;rXiwM+?n3p5vpP=vZG+6rdJn~jw}_Wz8$km#@R)o?5t^N({>cq3%*w1gS^5A z347aJYm9S`CmKGjRQF@`u`4>r65HU^kH@bX1M2PNdcdrrg16Qlm>#Gcp{CU2S}?0CsEh;|M*s4v2`o$U z6@e>3Co3Utxef+Hy!=odX4!Y1{^atGGr)uEE2vZCoy7HAeV@#)nO!Bzfge~oi4aD> z@Ly1c2?t$b6_}oa^LM-=9l#?R-B`Oi{07?vACT$>vVBvhxNh&U|H%yAaOc#%2T-JP z?gr@~LyfiHvv0g{V8TvTv>io#5;JBJmHvhMZIVQ`%z|$INTsb0tH%I0wFd zZ_teihhDMC-LeXg2l*|jzogVCSp5@(5C=oxGA9pCgK8{ptmL|T&B&U8eZBYMIw6#p zCSqgDU*#XrsAV>Bpq98Hpw6vlKj`%?hBgXYN5;L*eJg36w0G)uqb?DqUU$~uF*W$b zukK^ubcoLl?UGF~ag6jur!Nz1_Nhp)HrG5-)ORh;-a@LW5^W6sS~(!6u!gGILi+jt zJ))2d+etMzKhUG|TQN6OhZ}X@(+s^DE*_jwLhP09xpXHd_HF4J{!=CnyyMb~S-XHX zt~MBfP{C;XBQ)V5wzCy{a1v>MsZ{Q&+EKF8w8a^RhPJA<_6+v6?x`WSEToRBoQ~SO zCI&p^O-Ov`0@z4Bnq((2xZ0GcH03^r1uKJgL@+@k{1QCY*SXssSUx=Kx`U0aV24kF z{fTVP4eErW*ra!P7{_)U(uMHTMw929YQQ&oB;J_Cy`IUZrUrdJd?xuu&Zr$qzUMO5 zY!0X2c>pB0D{Q2_ck6!SK_|~IOV>ev$6K(a35N#5z)!$ma+J0(n!&Y7zQqBU_T%;j3oMLS;>%g;ZpfTt!y@3A>1T z3}x~|3V4jFW$3zlA^4h6$x-QU zyJR}lFKr12eMn@;ZC9|{j_)WMX(#@8JbsY^cER%3RxW^XYTzkx0>5{=IV*vcygzK$ zSVT-t*hv2T-ewoUX|m|t`7A}A(tKoa1$Rv#Wn3lBr#&@10r!kK7gS0T6O;g0_-4o_ zC*qhOmjprE713dFncRq-LP+qkoAHHzu0#6$|KImX3OucbIIRq6xoI7 z9Ozlh8i9D=Atw9g0JUWE)n-Vc6&x+}3}IE!Ll0>m$uL@{E~A%V@@g}yf=6DeDt!EX z{MWqsjb24Ro zq({FobxU1HB5*##+;Mq(iq0RsCl3`tu4X#cr@I@W5bM+A$pbR>Wf%01XB{XzAz~MC zH%>&cq~74vUzXBU7O`Y4X~{li!X+;KKbd&X`=Euq=uu!`6RK@98SJ-CDo1(9-2EbP zEEcTZsE{fJGN0TfM>Se$oPb__aj3O)u#+6nNJ<<$R4>=D?qwtjXm>%Pe zO9HKZw*WjBY$oGoy+XyFrJIuabjK!v!ryVW#i?(3zRC$A}?()D3I@h{yDyL z2~#r|NbP98tBC-z!f(9?R&Rd!xiLp~{8KNR{9+x92>sHrsme@@JdK0D){YurfMLNY z!fkW|7?M$u=8ub))URbnV2DeOHLCSX+%UV!FI(J~6A|{8LzEP10jzUK{LeI58_U$ym z+l>#pubLNH88=UC}CzbIV?fq0MV;wz%Ob^-wHnqkX~%s&GX? z_m=(ynK{QY0ff7~Ku0X`Pr(kx*4mmjJ z9jKr@;jZpTG`n=ES^L$``QKIgLcTKT<+>KgRR^F>_-p*Z zrL=5X{GYG3C0IXJ0_f3z#T*s-TwSkJ3qLxJ# zY&^(O-^Tf|4QTRVvZ8-vzn;1i0Ijj;Y}doyAyS@)$O3!>T`x;g?rkp{BI&OJeL(*G zWZs3W!~Rm!E26u)V^c0v9~1!Q!B71V0844Sj5mLbrq1Zul5-mvatASC#u$ptWa_6! z$2{LqA~{wpjoVFtTcoB_F6jZD8AWi1+#g68Y={N`NhXNLS%085Lk73M0^2-S-S>)@ z)#iF(iA`hJ!)_&zeoQDFzy9$dANi1>=0K6IY{`(kHC_f+ep89gom!qm>k z++l7C^h-N)1nhud_&*e``M~D7xN`)puK#2{D#&=SOdRWBXe6ElpM4y#$UW5k6zsfg zWqkD12y#9X@)XE^ToC4(#hBbHpI~qrA00*Kro3o+e`8}b_!&zD}C!g{TSk`Z1myq(dt?NuDO`Ex~|`A#2HR(;kVk7t=l(m&GR+ww3m%$josBw@7y@?lO$&wsJs~dCRA^#!Hf{EgAFU!}~_l2hk3=Km4 zf+;R|m70||>V~m>lpiXdl37gFou=mmDc#gWn9f%>#PDl+Yi%U0uu|Eblp!OIvt^0* zp9iyv-xihti-PP_)1z`{L)u>_lfMFP_6OunlEED#vJln?i)+j(%+2b9As-0#E3fAR z2J5553n<%H>j1$xe1&EN@Vw?<9?*c@P3lIo2QQAq0c(&))s`min!)GPgt$D(>xfVd zkhUsp4lV6|#+NP<)LTMR?KWf~F2J=RDW6I}i4|kue2^iW-!5X~FP`yd*Kgh+wOr*K zoBOK|!}7%+YeTkZLYIc}4`uS(+`meS2nzmjq_dWADbKKp6g=q)Uibl=jiw4G6{v4E zF$zouL0MAQ+j`_X7{Oy*wC{l&DB~i!7{Z!S!B8&aW{gi55xqDRteWAWkS}t8E1-P< zH~3<44|f$7kfzp_R)?u|9lF?ZMnoGeo$?JaG6Mc@kG~}&gX!MV^#XcIcC~e<=Ns^{ zLQ02>XRQ&d5srUQEn+dt2Ori2fBPdsyzSlM53k{qq;vvZOS1N6hv34&L1mNR4q_eaOl9gM!W>(6N`Oy6F{?A7~bn1GtXPzd8n;+4 zWD&r{Ue69Z67MPCeDu}fCoiD@IQDxl2mf0)KQzX8m?t)4Vfz*yev_22LsY zKbh0lj;;Var!9D4pir*#Tg%c&i&n>ye)}D;iF1^I>q9I4C-dd?N3Su_yoY{Mfponx zwR>SI@q6>ZFl@QjT*KfP9H3dg*UVP7-hCZ&_$?X;h0Q6BBLvoSwBK^5HB6^x-a-H> zOj}$w$!R(R?obf9cW&8Jp()dL;VO>2hjw1b3Taj2pThq}wN5825A(s_lmGeq*(BKj zf|m${w77ti8hf}7L7x7Z*XEl!Oi!|oV#E!!WTn9~OlMR*b>aIH=+;@!+vp5A?s4%> z*jYlZ+OwS2jsL=C1fv7td6w)*PW6}P^U@#DLcU{wci;*6CvV78woQU2v z;t}wi^)8yOFv+qYOPCfQPR76pm)sVjPo&Q5AlMsQf|6j`Pv8z9P0NhRu3Rm97o4BVZ zx`-uR`L>6iHpVtrR$~wC5=IhT)FTek-zS54Bn@ z`0s^s!rtuo(P-@%4d)XilYqHcVpp5X zEg6R_LD*>FJEXUk7CKd<7T9FCYQ#_GCyv*HWyK0e`|wwJONO*RN!GxpY1f}G|0t6# zq5#wIXCc(I##k6mV)X@m(R6ran=ECyIL9Q}QwAobs~o)fKEn7(r$l|S$YGISbNG$& zsz6RU5M5{3T==wfA25G0&>HlNtBre)n)CxXB=v4vXfiTeFeuD?K6gMaulrjNfJfenKLcz)-d?WRyZ(b~c#06V4bWc> z-K!E7S-?wGF6=iJXbk61q{6Q|Zf$E!gi%{Vx>^L$`GyxHWm@t2KPSJ6W@&~NdlUG) zmb!>ky5y%C2zZTo=mIW(Y0q0SK$hIn8Xs+AzF8!96n#nJF1J4f_bnS&fT;dbzR(_6 z_n*ve&v(9fCpY@erR`5OAO9yaQy``Z8EV7iEP0LADq@?Ui9iICP1Ul^CzjdT@t@&y zB3e9_a1Q*7s?Uf>TG^g&tE70Na47 z&GViIZ%1NC4NzX5)^RH>t{o`GUKw(>ou!>l5n73NrQV!0sE9Tx@_aXvqIJ?ndLlg? z`W+!O5_rl{YvtzYg}r>$g3TM#^kO7o3GndnF-0C!gCBYvR-Zm_TXk2up*COFZ=H3{ zqDj6s#LqMQI$228>QfVIa2Eu=Wi7tCJc^T_CHMnjIZsmD3DMB#l;hv#j{AwazR(PP zZajdRvscqg>`+?dE|yPMzHq1wXwn4Mw%nU6etWCjmpb`_0?0gEEp~a7s@z!MNWdM| zh|OYC`t^`RpvD0Oi!0^_aWz)E)%-3vU--vFO3KtA-A#o22FzqD?I(j$JSX}=) zAumfZ|;Ztz|l-@(2?Pw}Yh+6OV*W0Q!UugA?V4UwoiqhJ-Q^Mcf4dAElQF>=3*qGBzm1F--p_jq)AMK)%$=s{|a9Wz(N zAh|*TumE7bhF@u0fUkGki^;`3l)DxVK}^w93H zW2fAX0w7kalGVbbZl5*tw(<2V(>Cd39H@>A;eP6514v*9Ud)&X;2W~>CTTkZ9~Ou6 zm=MDG7ix19gJ=RAecr;~yW})nx^3|GVy@Keeo#@any`gm>|dDbDm{?eAlE#LJZH)z z%hxnFcjxQqReu#RK+O1QXgl$tQA+Tavbfe8=XCXI9 z3+$OJiYwBKtzmID9MFlPw1}5!o5JY7w(jRyd9iQf)JF9Hmgyh%Fuoz|{7?t&a+u%x z>nN2%p#BY^11R+C$f_zs}kCe{?g12-R=jh`D%Yds39_zoEHdv**gf1;Mjl(8-f>={IgieqicMFdp zTMY^}^AU9neOn;5#Hp#7n9onWpZijGdVhOxer$L5j4wzKkIcXoqy{F9TB)JOXlF|f zTBRNhcfb;=@^~BnB0@Zvu9gryDDJB;diPZ1_fNOmbxb4`#l|)7cUofDRX!Qw03+7b zu}Su4i*UyQa)LS0&4H)!x{q@ z=|#2XiHmi=c7c-Yu@P6Yi&$x<5tOCqAU8;zf~|)TGW{hhfO>tg_hZ5*v;W0&^fXAX zPvr7#4ueC~8`wDby0)aNnmb~DJ~zTb;|e297y&0%r5Sn|ohhni>ILg&^6Rd!5fUB) z1j(;9{tJ}rIUKcX4N2oGW^=-G!A>B4a<#9O-I$pi(8;~0`K*g;yaBGpI9B}9o!_6f z8Z=NzHN*s2E(DqV)o17nT^t4bJb*L?tg!a2wOk(Xv00WJUfd2fC^!d|Ldg-p^Ge5OBndQ$X31kbZRavh+Eex?@pVSBnWN5 z-C%nfnHep#W$u4kg(mIAPUOM9{wJeW5rj~>eo4hMFAEMbgzf;}2b=-_sr5h{^+ZOu z`_<3&NfvBU%!r-{LJ9k$f$1r>T__BfZwjINQ-UkrSM~_qV+B%^>y#i@h-}g48z>4% zLi>~=?GYmX%}L0k(Cy2CCXMHaGBo^hioBTZU36Pz%5a%;&!L(#HG@I+aQy0VCzU`5 zE*C1{`maZpg_@REufvM`SsUp5VBR4!AGT}-Vr7s7Fkp-t?#H<*&brj2CIm5fzD!{k zGUx$bGKFf9{`Tk&{P$M%kr8fKdO3zuYn-jdL142`Zo~wkgASbg_quzwF&;BfC-1+W zOOBCnM~mP~W{%R?UCItnECTWh znLkMMMDy!reN!k2sK_G1&Vm`jX8kG=62Q6GeUD0pQfqSDPf z=J-D7++AD_hnS*oXM*+Hb}mbF(d(s(DrS^(Maq0_Alx<}hM3D`48?#|7cH`o#0>H` zyZ4EBl~q^Ykr0lF&z2PWutkIlDC>=r@{gW_(_OycA~;V3Qm1n%l1a{0FY_uD074*h zk1pEi^(b3_9wfq1ZHHxzwHW1x9xGYbYIX%3K)EQP(*=hfd+TNlw7Zl8;a{hgwv=<{ zh`UIjm^e)VzCcxzi7F~zK--YN`uB(u2xMWK?uN(fgr3)>@eD7mp7}O$0?3jRT{F7$ z=nVj=yE~l9R+8jX%oP=f47C$LJogVfMVJU7Zz|W5oLz{K%svBagom8|6rc(o^OG{c5g4`j;|$x&%@)(tZ3>sPI;@0u97a- zqFXnP1znV!XOu%Jw$+W~-|b$5m~P8yp~JOU!Py;PjO50535p1@tA)sgoJ(NC$(C$O zFF;D)?;UOiB+v?XD2|%`C-X}=oQdCYV|o(IbGdU0BTP4d@c&$s)&_Ew)LI%J9b{8N z3h1dvTHd?t(DZi(PJ>9MHXKMj~jo{I>WZkAh*9eCaqg>JH|U z6`{f2v~Ym{;`oPWNmhNxI<1+MIrozxHpyLc4@f=m3k#BJ8C;d|m@M7AEc2}Tgp{vk zN;3v;RXAwd+gKx6K?t#BuMvgG^_W`oQ`GCZwTpO6tqoD4P&QW(u~kV@v>upz#QC{9 zsA1l0t4n=L+K_X$Y}6htUQ(OvtR0Z{<{PbXFr(|`7h4fL4K?V&ZsxdNFO(O~EOJ)Zaea`f?{ z%?+$JF3`Z7g4*p_3R?1rkWFYnSwHLjOmLcFD+E8O+@S_LA?HM>zwz#ow$2f!nFEt)K|U$OTemX9I}a+c8a!lfx8>Ff%cASnQ#!3Zy%p=aN3JpFh zs~hr3;muaxn5JXkhG7w}AO<{ny?gael17-R0qN19>Qsu7gjcuXoJP4K?GI-!?m~{9 zPXI!KbG-m$@rQDO0$;#q%-I)UL5B1uJr9u)u%tN)%*3)6CBM^BMg&O3af|bE0B*)D z{Qet^?A~nG`b_U$SuguF$?IWUQQE`42a2J7$>207CLZ-}d3|H-1A0xt^pPLe3Pr=D=Veac#eI%pW*yBkMUEOd(z(pL1eD|FoiyhCah=R-H@2h)sEFHEIbk>jp?=e0rk<~SagUT6ug+Zi((dgC^yq-OMlcE# zDVt01yTw0^lHO=V?f5kQx<(=TcBNi=V@fGwsBjnce!j7TXbS5St*7l;@UO9qqDLA% z1+3un2RH5Nm_;I1FUZ<24ydZ+uLgF$O#_~s=KJnYz!j$kES(j_m470Q8ficbUq*k3 z1NjEEIbDgLo3899T~YCFxAe&K#*MxICqhbhBIJF>L~a-F=+&=MF|!^ncawT2q+nx( z3@4rbPmE_kVVRWvonO*DnLdR*U^R-jW_ktn$6vx%*KU}b3kQL=IWI7=G%+b zzR6$zf;TvjWrfXswx&G&8wMO2snO|PN)E^{~W(5=`XxnR_7+gEH9Sp*i5;!Sli zxyDgo0ySKNni`{VJYB07E|k?jXr!=4J|tT zbIg8t3B=S**^RsiUsW2X5Mi3TNfpX+CG4%`{jg@H9G?6bzFw-3MBiP1U7jG7oWk+) zOW9(mp@*lNnd9~>;EI|9re6?X%l#%?i&!aG$(EB$7KzLT$7a3W)}yn_=<#qlbGLsw zq9=eIN(qW3wgO)zu1?oyXt|WMWBcOFi3f8ysgQq6+(xn-y?jb3LccOu^6WzHsf{Q z_hdor61Z>e$QQ;+fAaS^=-9>zadQpD9Xotnm6Y`Ea4`|!Y*S1B@aVB`AlC&#NjKm7 zA#x!6N+2-i0l?)Q(t6UbGY!^+!O*ED{I2}fSig}$2C;c)ZhdZDx*~5?e&gKb8$t2X zt^S-OnV-w1d!}6i5u%VDJA1Y&KSbFW#0#5 z>Y4*vf*x;+*PxEnbhKg2#l`#Duo zLTDnS{gXt0gwmFA0X6KNI|aT<4k3`LT2m{^@vQ;iAl)L|A1w|GvU6yxsjYJkzM*Xd zG-ZTesaG)zyupG!%>`C_J}WMjNzYU&)Nlm`(LkBp&y)Sr*{rRuE`qb98$p(udSK?0 zW}MYuB$hZqT)3W?HkZGz8t`NBh}Ak38)?ofD@@;?`7*2djYMX4qk($FE|Wu zo!YA`N6yQG^A&}ro9|%RRdUk6;5?_#yWC;>`~n8IrdMmJmEe3?=Y$VqE&ZknNlQ7gV*H9gyj!C6cQJ{lpT)PVzqYY${N! zntZbfzHO5Ce;i$VJk$IC*F~L@<8*aOa>}K0JrpXpZf?mXj0~yVFPkLfx-LgINfbgZ zxice|Z5Y-`h^2BF*~~&XE}L66>$C0qd-?r$9v+?Tv-juye!X9p=Vh;}sHn{8gx=fj z$8hgdsl4`q33=*}W3lQG|H-TFwN2Mm9Tr!c0voWYAo{m z;rBLuYZtpsczllwvJc~RZ#;mEcDH%bse80 z-sO`gWu@4DIm=(4yr{!1iS$Of?+nZxdl3rbdpq+GCI5_VG;voAQQIdy?({8N-e5Q& zLVi<^91IsGfEc_6-o7K!KqhAh^kcgn3tAe;;h}t!crSeNOwJAGw1X5;F{5serSuPH zxqqHZ!tLUSFLm`bIprzJCd%*%cdB?qL9UyFvBuaRRoJAGYR(e)t)Gh+cwxK{pM`uP znq+TGcmWx-Z#?lM@*5O^SdYaXrKZQ!a4Ll*R3$nGsfJ6n znZbMnRVpO?sW)2}%N{F>>qo_dh9VKk-Es(dhE^O@f6ASbR~p3b-&7FVPEL&jDxW$m))6Fd`}e1 zseoSRM^ie|qra%yM#fkLSGZUrl*n!6>{itpPF_kbvtngk#)RWpYWR|Jz>{E^Y5jAD zgq66dTnOkLfgW>ug9^=io_Dc9xJCRW@xhf|_JmlOB`f}?ZkIRt?)TtT{@^@D>>=>h z|8z9rJ1czWBf~T5WunTUzXc(>ev@wiE(f(f?9c{vUT zV@wE)>?M|~4STt#GFuxuBSnEmXWSFpi=9OsBX~FlPVfIC^;%^=qw*G)=t*<83pgO} z(MkztM5w)-MCFlFbE0VmRp}GUyYnFq2DG&hc0DQ{>2-kui81QbsJFn$(!8R>5gKFy zu;3qCo8-7?FBWArBBsvmq)V2<f338H#Z-iR$lGypLF=JXhWpRJJ*mdC$E_MON2InxEvZCv5skC zy&C@#^@lmJW&Th>8K=pJv(jY^lp+i^`wTa-}aOQE9t< z;H_U}3KbSmiLJCviI|Ng^J>R*;A%4{-EbY_U`F14S~Dh*s#7SJuCTBhpBAUut6A)K zh#EiT(R@HuVe(zW?Ml%?x_MK5VDqUj)c_0Tkb+w8G=ir{$|m@hq&E(Iv~+%4v>K)33z%=JEeYls}m;EX|-Y zhVc}@9cp?;Ax`A1OShgax5{#~Sj*hq%1rSR-dUe;+gNJsapb6I>!Js@@nR*=iS{rc z!Ai1k9i{G>`P#)lu>WghaGI-MeijaKb*J(ICUm)ZH&#u6xZKmbOk z%$*;Re`1d6SO0k{ma2wUr^twnVb8pAn2XsQ!i)5-UA$6M)WvByL|XQ~gR80NZmjU< z{gO|l6<3W)qgk?C-K^tXU@m40dx{==cKMxjRB6naF%9L^xXbL%!vIy>7|0NwTok5# z29>{+Bl5RX>VHsbn1FAZsNB9R|I z2Rt%czZ>e2erE-V73stFkw2?;7+%CpvrK*}P*7PPa*TSt5qb8bTXM82$}W4ui$Icy zBx^Eg{f4M9BfUv?6F1v!tn;&CLggL>WMTk6vM2jdn9O}+^_~^;evNti8ILA*1L_O% zksZCZFHL*HvQ8G+R+qD6S?W0st|g*nN+6EC8)AS|D7qKJbNlAgwlMa zwnBV3AZlW%Lo#LfJoT9Cg~xD{yQJVp4l>`|lykpCNaY%8mjsgjClROCtut!x2&p!Z zr_*g03mF!XUN1g8-W5om>vcc>A4m)E;l}Jnya?gbyxT>!sbr(XrLJ;0QT8KB;GtQ| z9xl;R$PCQZ$FY|70uyXQgTB4&8wMo8OEG29iDy~bb#qG|Cj53r*x)k_T{Y8Nwbm}f zFgVJO#KXnB=49CEx+-(th2%EVnA(UDl(=h;Xd$!UJxC~8RSb?iWSmiT&WPH@oI*VY z;WD2R?!74u%aBmzf5yI8Ps&h2iUVQWx3im=aKPWI7&f?5!KT%>C=3BW^55?SWseczqY~x>2A#vFY+p z{70hIZ91-}sCpPLUOGi$6qN-GMA3)&`x4`csgvxL@DSY^99y-5Xcp8<9xyz3=-8Jx zR=cPpq{iVAvBb(HTy5pSv~gQZp%f~>|{Obn4Cj$ zxI>oQ?_lEkqp)-B+XnJS>o~?oB}sVcxnMpD!-D|)4%jPuO5e2f9n46vivChl8~Y(c z4mK~-e&mWjZdF&WFquz-4nKi0)qQVW za2jg@PhyKz8>LKsXSl_rxXf(1L0#&;?hdhI{V;LUn>P&eh+SvZx;2Jcd?#GSerVyi;*3L3uv2*wxr77)@_lV1FCC>I*mcV$*kE zw+hBBgqiP+6KyJWE81O6zS?e52pm*f_q9lv(3sUl07rg=_bZXV|bFbNxGXMy$T^rHpJNXv>;BXawXf zVX^YB+bfym^I4 zvyX=Wuc&z(iBuoBJYxD~LD02Ylx5n~$Li&N<_)0SnP?RNbC&9slX^Qu9Cp+lWpb^0 zlPy1v$EBA<<_q-xIME-(g=Xo*ODyw+h(mK6I2K?WZQ*-PXw82pTIxrlO^Cr1`yw z4uh)luCl~Q&-()^CF&vg(Ar?6{~PDrF`2sal=M}4S{84wT;W@)aO)jq*IUeFqBBxH zYvX$5KL>c|1Vqn*{#bw;5}-49+eaMTaMBW5>5WdJUSo#-Z@2#rDws1!FE;_i#Or~4 z6M+vXlX&|{Eblx4rFxQG@1MUe0QN=KR7rc~AT0H{bDQSo^R`4_e?;QuRXN21;AWXY zUFd6OXaH(*HTXEr7qCHF|LHl^J{J^lR!%^I=~Ga^#t^1v~-Sd8$Ac+VVuOpD1qSBqwc(8-x}8}Q0WEUfXFk&p zAUDp!SRVRVPE~;e8&#-zdO*82CO0acC`FN+aj*Fs&SzOx5mvtjTR2H!6x!TbYV{pC{(3GfT(2hYoKJ8|zy z*XMVtlGzA*1P#DUuHHN^;Qg?q&-Dkd$(QuqX)qwNZM-TfU}H{VUtFJ>gvn0owLgQO zJ2YjpwB3rwovc}42c*$)LUFQK;2Vm8H~RH0MPU?F86-|(w@2Wja>$lK1OEh{rI5R} zDQzwPK|n0}31#0shhhn9BP zka6*^yt`CC6HQ}|<&^Z0iLUg%BkiW<6YYe5ee$;4_8ng>W8SMe91g#iVg@Q%G+eED zx?)7$A=mK*z}pJVcI1rl{Rq>&B$dEpo@qSYnQXub@7>)UZ=7;xk<Nurg7K^y`a3X2?hRWoA3*47tXoNDMrgH3po8=K(7{@XSuN^0k%TNl$1%WMgVNSDJXWwTj% zTM@IlADj}-)Py?SBwY@-6I+DrxBl{~419w$?aQmLWI?bkQIp{spo(f)pX25iv2O_G zRM^lP)Q;yKyQbGG=oWQV^KN~)uxAH56w8pn6PXbZa^IC9?k%(Z94XF>$#+LOS=D&O zZhH*U0`hDIe#<3ECF1)|Fh^O`WT$1qtWw5)$D?oD66`t%xc+RvaO4woc#CU|xxlt} zoX8lg0Ul22X59{`d63C`7x~;Da9Mmu`D1ejQY-Zjo9Ie(Q3@~dx2}D0Pv=r~D5*#^ ztN-yVw6;iDJcHa`~mq$|YrM|_(|PF=SjM?6it z(D}8qq1=Ng&5qIM2UPLoTQMr`72ph$evabNaOkUxR`&AL8c4H@>Sw{!M1XCNKRZp< ze!4dfosKA#PC7tp^i^%UW)bn#L#CLfp}=@>c1R1(OWB}hQZO5R>(oUIg-_LA;N+cj zaUohdmT4l+FkHf64P&Y`#48sWr__$FwY{HxC6N}Z{yv7QE4~~39{1j~A^autLSs93 zGtK65P<6^(6Skm?f|29C`tL{t@83)Jrs13W-VAJZey$3IQeAb2A5B~he6PenKlV~z z!2j=K7%`b15^`ODy`@xd_8sgv-vlW4&Gk>k0KeanU7zUe_rh<@GfLwY=lyx6D?*oH z9Paua1J;Z4I={EL8sLcMpFh68{SWEWbEv@Crne_Bb(2kLrgq%&)Qs}JZni4Fa{K1E)my8By3I3s%rdM?Rs?bZ z@9z9iX!_k&W|}$ibT%`k_HQ4umj^%2hj|61c=*%02sozsjPNoAR$iqiOFib=_t398#vE2JV ziCoKT;8D9ZF890qp}p`p-YhJO!mr6M5iJp5D-Ax-Gw-dLa;-8=NvGQ zn%iEr$IXV~^~BLOBmar=#jgeh!%D=zKXqy`yvYjTQeNpkY+j2uI(@FuFpai9Eqq{> zB62;12U>;O?^%l%tS^N|1cz?Gh-XxBY}X9@l|je*_NhvwTxT#m;}9G3W%wB_E0S5Y zF(((=^PD1omR5SKI)`E)i-~aXTJ?Q{7bFj?`1 zw%EGVbl?9Zs!ToRv4YYgQz{E{H&t3oKK9@uCOkxv0Tprb^+Y!`!+L#E#`U|rqi`+b z2}yQOOg%=h9)kba8rx_7xEQj(lq06uo%tA>gnHoBU2vH1%#mKxD~Nbx;BM zYyAAC$a>{430aBVMq1bg>|Sg32Z9B8AerWf9Sp zGf6=Kk%G)S`~g(<9eP7eRK(R!sRy+!cSe|mOvcCa#t%VF zlxiL37m{v<0(Scg)WU1I#f*{aRB^6ZC5?iC&QN&lAL-XNp0ir0e)a++!$nj;M@TbrZy0 zc9O+?-j|kaO4%&XQpXxzG2Z*!WOxgy@(%R6Tk9$&9S9cXY6@XD*{ku^Vx-n!Dj<&)df9 z|0}WPYUW0wL5gYJQJ)m3g*YK+SbQQMWa z;*3-q5Bz@((t)MUXlj8>)yL2D0m28Dj?Aas_Lc{Jyw9dCsA?MQ4@Ad@A*P}(T$ryD zI_<;=YjGpL;vqso1xEQ{Lzm2@s*sD!QdGU8r%|CCu9*tx160VL9*j$8wT*J}Iig8s zx9#uE{`%YzEBtXNU@Obe+O57i6T^p*x}iEmD)A%M3xzOI)9c*B0&yDoB)WN~oEU8a z(KHFgjK;5e`s)A9)?=p~p@YB%fxat8u5U8&{7qX~#8S;cL#Vkx=B`Bl^jO^tdTO?; zb=9+sFIf+Je(z>S=@a}`q#BGp-dgV@cQ2n>+u-HImV~fv6=qeDT8I`As<1Qo1YiBE zX0AstqCtB8`?99WMXO*1kw{RU-JTwDyQ0Nwz|R@`UlC(UEQ!`0YLoL)G@c(zCObA^ zg0rdLJ#N`;Rv9opSiO`_Y>B)s&7aSZ&%lki6JxQuS$__4b}&!rFMgyrLqh~89K<9&olhMS$mj9}j<;c<|I`m(%SNSxDp|{@t+~bqvRObozk6he*T4ngGc!#T#$B|(h z>W9uBBohXM33L}r;_NHF5vxczLm;Lx+7fV0G$GWA0TTbYen_isEGUFoRb;ge?msKX zN}>hPD$-$YfKlkN{BK4CS-7rcCG=N%LY?IwwkjnR(_eKsOX3d*FkF-Ia&|8)=!%fa zZ2438G`bt`cRYTZ-GgoAgzrl&^B5i$ReHY=OEzQ#N?l$UDF_a&y;PeyMjzxmpYk*~ z4tpksxG|?Hb~Ibd&U{~GZpjEPgu%K5UUQ8N8iC)b|IF|9ee!wAI+h*PoslIL2=GrZ z4z4{e`L^3bk4$*9AE;)fdZg-!-Wk_UB2B zIk_^e&6tR#9U!e|9eZo?foMpvz0$)lC-tV9>{%pyw_7 z!74x5RPr?<_RutlWkMEiP%a%f=KK`n<=ihk)pLy8)$P~gD`Kd(eM+9=v!%!T4=ok- z3AN)|#gXV!(1MQ8MK!HDycy~^C~mKL{Dk9|?FucTG*78w9?OnVe zX6EI+@-M{enE;hWGn4EWSd}@GR?!b1$GO*_1rQC}U@CD1ReGB_X2j3VmUDXRPE{r* zR{lrE)m2nobP7dBdkTskeSQJ!Xp9J<{&F@vXJo7NQsx$^MsSF2xQe z21T4Vna_n9Nxp&yDoQ6q%JV2+g$X4BCnIeac{x#`w@=k?je}6N5Ubx|ef#5UtYGlBtkf=hG@%aN^f9W8Ot04tlDJ~W0B>-HZfJyeJr#IBwxKacA+@OQP@D;a z*;v&PIqJP^lRK9C$Fz-ca7~?h7jB69yBS>sC>dDp@-1(%1>GedyZa)EytBkx; zynmLG(t|DtVM7x5emixzhSp=Tddr-BIZuuI*;do!!|&l5vA=Qs731?gvbx>bzocakr#{1YUTiYm5)$guMiShtHMD|;JF5|-prw8w z`+v<@?jU#dVsAn8PhUH;)pC|8{-iS@fsp2rt6c%&PEHGbkGuV-CaHOXG*g{j;MX{; z*R7IX#tcZq@YA-Wz$R{Sove(*@RSq(O)+?YfV?Ygqh1@o( zD(J8Fvs!T`tDN<|9`aKUwbWTVTL-Pfgj&10iGX*`kme=oe%4a3uX!9d^9~t;0pb@j zqBr@e_B?y8c&4{cXevrSG>0=0H-4yq4H>I(Nq^8jvgteq8}aRSfxRhG-iOCBMeNkf zYF%mj*s~MG^%TUhf{nwn=)L3wLS>1IQeTB;25#c@+j4L>HwYlTiOdh&0VMpR$A@f% z0$PK~BBbL(rK)ZvCn_$NYJ)<%dBzXw(L>jXT6I|``uLYV;utQd^34C1>Wr`MgfUi5 zZtI!se?YOXmU9y$o=e>^Y%C0hS}>{-ca37!8(Bpb6_vjE%2jb|e>w+%#I0}X8AA&g zxTA+yjmec@6(+M&rU}1nZ<)_Jr>68+$-ZiV6T{uYPbUgj*(L_nG@*+(?%hQ~!2 z5gh3cEq8bY^PCD1vk^&J6+%0sR1-IK!|L%~lj(e6Kiwni_G^7a!+iR4n-3OLZj{n0mWRN#in2L2N^oL`$LNZm+e1|!X-yDoI^51^%oLA9JM zcc2fN?G+g5`XA6AsY~1+>k-IB`nNr}fcL=O zZ(3J|{zY5;j<6T@N#K99j99J#BTs_u_@oIIn4`7a$PI!cf)W~Yopn*|h+BymdZ ztZdv+0ciimfb^5>)Q$oO!UP*{4WS%#wASqy0jZ!h@IOc{ZM^iATi}PSHgMQ?f+Xs& z<%NIU0C8<+z;kz8^HLw&2wO#+3Zh{YPF;V4w3tsj%ji5L=4yZ$jh$o_$M(b#Eh3eP z4s8u=?y5vWUm z4YLIiV*KguH1|4S26~FNmRaRWlB_z=UwLiPoe_e zoKI3s$J4#xQ)~7hb;-WLpYYbpe+gP5FQu=NxWyXJ#y|zUu%HE=r-(T3PZEZ|8hSqN!{!H!)s^4Y#;if9 zoB8=Ra`S4AFE4>kP{djblx!_R*QK5KF}uI310mQ1YA-zp%w6x-O@U}((}|+MNV(_T zaNJQ}v}%*GxFQC&XSy-3CV%KNYs=a?Ax2%5#&C7tp|jQh{&$2r*E13S!xsLBOCdKi zy7$jg5H<_!Khq;V?W@~+F&=mOs9^)D=1Bd`m&RYTx@{2kTo_VJ5-cZiAvnrXUtEt8 zsCXZDQ{1`kZEKPKXVV~Gj2+5k9?0wyUA%yMLK;m6L~2HE2tptsq-(T2fF!h|bQo2g zxkZaOIpEQ3jo7U)QBLM4&!x9zp#B7kLxo=y+H96zMA)X~xpCiTMx=cDrgeIUptDb5 zKDw{qxjvvW{Hqzcjc)z;>)Of9uotCX>YGvC>cMSUmPNh+nkr@J;VL;*TNSgzTuz?X z)-SoDv}_o2z%vjoUp@~aP+I8}xJo1aWVKN)%=|swC%tm3(w*aa6zq;VS^Q7pDK=n} z9oz^%r@If;RW!@cfVfTQy%uhE9}Y+Ot3gTg!@?cg87-R2`V`HVZOzl1@ewrD2+qo4M|aU&yL zMA>vQRxV7nBH{B&-WHR%Pi&QmVoq-0HoIO+%6u)fI1+u6Urms{ZcN-y)ljWi?Nk)8 z`ZX%Dt;pSCx`KCDa0?Wkl3n_NWmDLBp8p7p6xIqi+gd8>sIA}U5xl*QBn?Nj;RvNj z+3(4SW8A!`3RG(33a;oE&*;aFd4PyaVo$j+4=AXV2V6bk`pJFWl;DvddqGwtT#T#| z(gYVT<`^VqEKA`ir#}kk&x2cd0skrO5#1^ABO#k(k4=OJboE7D)h3prQX}8@Q!dpb z)HZ%uMT>1Lv;0nABmqoB=8fG>FiDx@4UJDCGUWE}g!j_Zwf*@(3Tjph%w=7aXS|?$ zysp@yD9RzGbs3bQv|h&rrGSZj+F4fj`C0|;tzzQ8PFIesZ=ZA$++B-*mw#+Mx%*t& zRJ23Gm5^n-HCk~e`DHtMjCH2|apc+v?9JqERHwp%YSc&Eqaw-lJ!3{q(s(gl|5GBB z5%56Iy20c~k&7bp?xuNu=3Up9*_f*@#AqGZQ~qq{A5$;|+?L8%Mcd*U z%wUu2aCR;HN7LB`cK zzPZd1U*r7)yU!u)A}x4A$WH{*jIGtG6*G~zEKzZBCodj(2Kp{%_75bd8pl+wiPy1R z&}o0Fv)^|M9c5nn%)VL(*JOlxSWw6v%edwXjF&r2KJJA)&wt<5Pfhuyc_&R>t4^*0 zedtbKX2&P&0myg*!_N1b3xCg|CWJaPO`qC847e~Mi)hWqtw7B{KlJTE&`FIaiYXIu zlVJJo&ALE{=uc$=0k2Cp2t!}!G5DXv1v4_qxnqbX!^^BN``iqbKV4DPk~}p`KhuS} zJnE6E(St7XmTLc4Ccb#_e-fdS#l+VxpW}f451(Q|8RVLS{{$(qSD(#zCDvdTvnl#fa%NJ^hl16?h(&CPPKUy}ZpoXeF5ZbZ z&yoCw3Gcc}@qq`EFPqSkD5xRwv0Hh`xlNAUdY0LdaJKIdPPXviY(XoD`I6<>C&8(^D=Zj?uMi&ro~riegA2%})PS$!0m+P*D)~ zivjHQJ%*#=E`l5x`_7%prK`BaVb`J!1hU&EU<aZ+1-U5jrbsOJOX zch78S=rVYWTxUB)8%@oPW(;DdWy4KadD0o0bt(4y@#P8f$z#a);UO1=O zWH1_t$FaV-F+RwK9^W=-&w*tlLArIV$G}n!oLD`$b7--{pqp~npUW|?; zR0TXr`@>yHp-oMvWl}s-E@C4yjsJ;{+{U(_uX+2#YS4*M&2TM;Az7olLi?67gY&$b z=*GmZr~l2-AQl9?{W?~-dbniRt>jg%?_G1D@R$MaT{s8boAv$6L++c)KbokiJGqrB zayaEmR@nN_-|8|@&hy6f;?`2z8?GYx>yL3019(Gzq$6wgE83@#;FMkh;+4@VGntGt1 zw89G1k6iYGXk)WguqS3qgq)^=IEws<&Z<4c)r|AtmA~#)O1XYM{ zSMqWf;)qxH{JaZjH^JbxQt)gb^4T&L#_(7|xta46AfSu9nIEpnf>l90FCvL+!=rLc zmmR2enw-T6+7y|^I;9GqN^hS0tq(Hyv9iR&uXg=&1viz?$=en_pm`0o9Bx2mT~>$? zchLg|(a((X!@=z!o(cc>YoMv;R{bD&#xOrjB7HN!ME(*Fn1!8x;>!|V$c0q%aYWpr z%Pz3HuY`Zz;XfO1C<&|BC+0`pIjT!1Qc5Fo%uVJfj+|KEeO@iy>=6OF7%6yCrJLB? z@$1_T&~m;b&zp@c-yleUbj0yfr;hI=d|gXG<1{I`a)+|*uc@WJmew64J52Dre)kzq z{-5R_XUPb~KgGjMO;1C95b5ea9$GbgE0~{_*&SYxZ+99pQzdswuLX7JniDGJS~83) z=q5y)f-Ik4K02Eh5=LuZjG>O?)mR=(&iYY*gbKat|He~o=If5ZH&cbyrt(ii7S_Qw z4xB7e9X6{!{S@;2E$Hu@Zy)EyGn^9Dwvc}l0&x_(*!)pf(OKL(*D&-m&%Y+N;+pL@ zS{1)5nMgEYu$CRt+D%^VGKIzSUkYN0-xk^Hr@_cZPFc8%AB4_PSOkWZOO&3B*iC^A2FI&Mf-_|u&VjKDGF zAi*PQqQrJalSc9lnB2tBO)?JONQA4Ybl^W+G)#LV{d+AEzp9b>ARHIh_2QI(G)o4} z@WVVz-BU_l0^|xlc+2CY*{0KT)HY)2L&u%+`T8E9b+ob8kJsIG{!s9|86`lahp(EX z%c#_N=luhs#a)LqTO5$d?i?Xy-FR~&jgvI5$&l@S_^_5Go&p*O+BgLJ${Q-YtOmZG zC`|KHd^o6@5pnayWdjFv!hpCntK*c!+<9G)XG&T1@_ysQu!*SyV@q`Mx6g@Yt~3f{ zDr&(_XyX2)tw%)@tqNnPlFnkr#jdz72j=)oP^!uUv7Rq_;0fW>Td<}7^IGp`8_5@ z2S=3G&6M1KA$LLLP1BIxtHMO!Mnyp8?52(qGiqzIXlaoVdzcOR7|_{fG%@~>es7VL z#jU-B&^Z910f^k*Yg&J(f>VBOqaNf zl)XcH23^W9_TameZ+afnle;D#8UfOUa3<8peVmYPN}%0_N|m~5lK&Okqnkf@vVQY|8`FKo`tW;qAGTw3>S9ZoWEqk+P*DxdfV+AeI$7qP(B=A*v^ax? z94*0AnTt|4oP9No)7n6N$;Pr!`w;QYhS+JdUIQH zF-GWs?MuoEY77AM7pY}tDwtUHn56oi-x_s*ydEU?h^>mdVJH3f*5l<*;KgNynnBv;c!?|-DFK^hlEdg@4t*fN=#S)J{ zS%lZQ;U+a2y#=@?w(cIO>^bAzy&6_hfx$KS>`%|v9D&$sOZ~~yn1D~1`6-Kpn4Swv zD1Dz)YNU6RC&`yQIxfflH6QSmDwGP;4L#NIs71+NBP&TLghYM2%;rWzN~X-jdD+V51c;A7y?geRtkisu&w?+&$&U0(4< zjBCUP>eZIoZZX%aa3dqY@N1GH7meFLldMq}#fkrb#5pg;0nOZp5k4U`{Idb(T#tmM z!gHn5kY#VHtiJGsJ-@~kPI3(OixAsr>i(v?+m>Q@vAkP6Fi@$dz;VT!%!z#Ztm#Ee zVoEn-BotuZu4}z*X;0H$p?*NGrOBhZf8a=>X~)XpxHhB^N=C;;ody%3X%fYUXXew~Q)w-h~7xP7xT%JkGd~wL% zasVXGZr8TU?Hkc9npu!(>|^Lspn9M#YaEO&LajQFBJD$13^DtE5~@wk(%XRXx7N74 zV|=)_-)YLqa<9UK-(UT*-BM5sRn9OQ`-wPZTwRPlW<9yPQH2cNSiz|Wt6xPu-_>RWznHH`Zz)nuJDz#*74VBdcYJb-{Eke0$+ zI)9({FI6EW?6{c;0>znmlg#r0q9~VtvGxnjQ<5T@b-zG|`OW`33YE9<-x(b~XX1bA z_^HCp^BM#uS+qN=PF!bei}%b&e<{WH(QAsu;d~BSudM8xfnu>x~&&TNAq6R%#Y8%64bs=ZD9;;G8g-N5I6C-cbm>U!-v?=Fwrs77- zV(ICT!Ty0#!-wN_1COUh?Dfq00ZX+vFd1`gRA#@dthOmdDB!9Ti$}++u{1cEeC3J=eN!#8Yq~YZ+tD9AY~kaop^^B!uw^!E%Kl02=ST0O=Mk6 zI0Ana%~1EB5{64%+g(?aFJfyd2aD3fjyxuQtKOgUSM7t#-NpHjL7inR+zY~#i%US0 z@u`7Zl(v+k3O3i4YC3i#vgZ|JsH+_Jz8{N~IT=sbj*tI{{b?3JRd}kK?SDmz_FI_c zCEP?y4na%wlhBx<9KM=b+Nqy|tA?pSQ!V2VJg+mx&n@O^eZBRRc`t^|ZV@@8JAHAIK4Y<{tecVbz!^)n30}7P4PDoV{WewPXAzq7&P}fg7uw;gq zC41f=0Am47cj*vr38$MizD;ooqdd^!_i=IW;sQFGFggR{aY?wS1QGL9stb%sO9|JS z1~k#ODU1J;Nazl82MxxJ*>VP9Y^JMon}}bDReGIW zpYbOijCf%wPTpZ?ugtjYABFe0x4y7gzt0P!%Gmxj(=*APk}OEf+vK~}X0Yc?g5sTN z&nxFww|=!W)YEfN45r4*xIjtu6S?Eq&BjKXEhRX1zQ30+ALFbEU zpwJBWUjYV00Ak0Eu2?#`X0<^DqI^bF2u1qmC+PBlVDe_1P}<*^rpo;n{aZhg*IoA6 zWDU2m@Z!!{Zh1gWRTaP>22z}^mP|6C=Gk*cOTbK@FM!q_?HIgFmz!p*U((iKINss7 zF|m|J;F4DJJAUARF=N((GY0s|Eh5g=3AR9 zndpzG)7LXTGD*9Gd1Qyo&$k7?xr!w(j9zoHbbf>rPakOndKa7rZNthEJCF|)FhyU9heVXbi^0(Dl}dl_o%q+#O~i``09rdFwM(b zyh5tF`Q^9g4O{F87Ba|z`T7~q1vptpX4JP%CXozouGdFg{YOHuZ-8Y-y7$PW#{3qv zLUikv_l7hZG!3juUF1@eRL2%8DrCGc7eb!Sr84&1SJsuMwhqrc)FxWsa8+en& z)ns#t5_X7T^3scAP<#<>oL>A1O>?#`4$)9n)-*|i8pVp##Fb2&DIr-~eK4vl>aE%3D;PT1+~K^*0N1EX+6{*SUWiZhp^T>EwR@e%CXXQO*ti=*uo`oFzX|A zLAD4{e|kHXJ+Glnusxg50KM=HnPXvsZCTXsC^@$aB^x)PZEHB<4P?=bao4H4uyBz9 zcLF{ceAtT{VV+Mp|F6XkHCXtZ>b9iU7EExiwhZ2t6~3N5@A&dCGud2jP+_Fd-LBo) z3&D-#TkULsCJkMi;DNmWCMTzNR=y4YJ{J|tyW`zy3r?QYp@=X>UF=gHtW1EEav*mo zm|rUXD&6{;BL=*W=Hv_w-coU$0WJ|rc!_G|F&&Z~w}9gst%#$bRy)qKein;zL$6B0 zsjoimR?SP|ZLOT2cgP&o?imyflyd@S8*r?EJ-b-q+KIevwoRb*QGUJMNZ%1(jlxlE zolM8)btOzE;)8+;__4+wJg1yb`nYDx23h~obttppvDf(J8+CLqCOcEsC(fPjmM5J( z97C||%CUvUuL*6ND~O#ZX>qv<`Uw5tt_OlP8z~YfSI|O;t~&Zi9b3crQgz&l#oL0A zC)F#vu{$GlbfwoyLydi}2Hw>Fi;kL}aJjKB?<`i(g6JLyaek*Jre7qfEltov)*8!+ zk-zV|^JnAT#A?XH2?oe%5*NBhdlV?|p{|R6T81Q?mUgYmB1j+fd=6vCm*o)`JXoCn zNjNb}*YEb1O9pNDjKf_zPKAD`Mh;r(nXU;A2nrIBpPQch&qgkdU+0SV`AU;bT5T`) z1&8Nt;G~efoy0Q)se{bE$r4C~VS>|=nT{Q~5IfJM--#{#*&1puc-C>(PS8;gROU;( zs;m>b64s3%*M}U(7j*D`<<8TwqUi6VIjrlId zS4J_0g@Qb9MSMt(g`Dq2xmaFWp+<-rWgcer)qh@X7HL->CZC zq{mvD`I62@n2JlS$3kq76F*IKO+Fd;q11CniZ|>V_B^2g>h@O#-ZAYtrnBeNFI9EH z*GL3(G@!Oj+q&NV_G7Il)u)&uJ!FtBVx)SJ+1;9Ut7efmIOE6ZPqFX1*K8k_5|-gC z=`LYL^&Q^s5_etZZqEhbX9x7)fFhIvu`_k#UhPq+iYPY7X(p{!SHb}?>3nC(Jm;Fz z=3?!(ocv&it~bDjZ-vSWEF%6EuV~sG73DY??JZ+pt8Wk2p|{sJJlBjvDZH;^eWu11 zGNAqcvak#1ne72q(>AUy;llA?#I<}bAS&MkVfk}>m7Y>5K4Ps5|EDzOL~aWq9;r*% zg6d4hvCu>Ay0TbN7n@ZiZhK($W*5yl)3<6bDZWfty}0Yyy|Dq^)vtVYCFAG>cC*o3-O8- z?>6(P-u&uLr+=dSJpWzWNg2wOBimU}6r9bgDQCVGCReg~YjNtMJ)299C*uUu(7QJu zq8)fb6S`*J*~{xLrxd}hx4vx9&L%f1lXR`&a!+Z>r}2rWYPhJvEl!Jj9VMQyM}jkx zvZFfJ&WK}5`|Y6%D)VUth&*lgC;w$!R4L^3eyR;R@la2pE6r~|ZGaZ^dhv=61plQ= zunkiQ-k;g}p13g8(|s-vgCQapx!l(@{349185o#|vVu7b%N~EB*^@0E_?4$s7w4-w zM?fhNGxeq$sLhQHphW)^*RQyr!GrYQ5xC> zs@?ny+z@`fvhU1f*5SpgaK3$Bcg0TQBFKj)1GXHTxcxoJ_rqOu*S_w4gi89&Bgh!6^esVT zK&F9S2IbV7VMcv*ak5t74(v|3 zU3}M-TbB$U_!aM9x)9SiQDBoEQt*H&PMO~2DgK24pr<`?fGDGT&)~wcX8W>pbPRhQ z+(Vab>-)I7HOIBBfC;t!G1Jdv^Ys>-UaY508pQKl%Lt&}kR79@T2~7)3TolEhxVHT=-4Hmzi zd8JL}evDStuKH;IqL(qW(3_ti|K!sH%oq6Y7k~C>D2R%!`z4dM_r+kU*lJdCj9^wn zrSExwCH0}IRxcVl9~0*M^BQKy>_Q!4;7QGI;^bHTJtDsbMc@WiDS@LbMQd-w zs8A2V#mjn2njQ!)V#Qbm#wK@O&;5YE*+~TmS`%aNLxQ74NgXNOB+5dAPZs}!zmh25 z6hi)Wayu?M0Iyw^+LZGJ?5`uqumy}F`i>3d97ZiOZKHsn-g z8N9zEH%pWzC^wlyF!hL`2mk%oOR__lQTH)hyneU6d8FL_Eo3O^w^ntdaMjn@&!3kd zZ?a&UmJl+SWRAiSu{;IXrxK0iOFsnw`Lm#Fz0UYIj3r{UXPqI}2ho&bMr8=#M% zj?7)reeVV+!(x_$`L^V$UjsOPTAq|a%S){ECDmV|88?}EI~PrQ$FA1|a|%)j%%@yG zg})&#AIQ6h@*H+3moMvo00F9OHg)=pCxrWe2OnM=9jeAc5vOOXoxbI+c!`_0W&F}U zsD|FyFR`>y<1UZ`dfP7BZ9p4!yxhH!5rg4N{U1kH9?10n|8;*pseDo>l5aUGXE{IR zSQnDy+#HL2O0H>^#N6vtDG48hicLYw1lL0xlz{a>Jx&V}LD@g&bwvkGlu-t37JF~p=nERy*cdR}kx}|ht9*X8m2pX&OT;joLEq|a!HZrR-GXR>$ zfxsK+Q#A7d2K-KMaLj`P0<lh6B)cQYG^+1ey9p$o?hX9;o8#V=_<+xLiVmy zC9>e2Lou3P9S@{PF4nVq$kM|=OD#ALBYSvSbvq?4S;ex2uHD)c^mWlfJWD0khJhVb zv4NKf78nUkBy0wS(d&EcSr=SOHQ82QwCo)L5a6*`7jF}%A5pZlkC+9|NLRE;|Guxi z5(K+4r^N59GK%wo_LmpyaGeH7gE%Mujac^B z;~)B3AOv0Bd0LHSzBR6Hj9P$q)FnxNfsiv6EIxYm!6EpXH$|*EHGexH<_#xg@<(kk zQ&t5(4~U>;D4O)*TvyidMkXWVcl+mW$rCsLWvv6h0CJ5elyzO0L>nV4AYIKE1!-;> zJnrv*I;Y_e5M&`-X-Wm5(i&7gyK_rV2NQocFKjA-N0R1O6RPgV$F>rpl6?=V8wR4Y zcAnkujuqEbQEgu~5Arau7T*=3Hc{+>UO-B@NscxQ}LjW#16hTotnF?$YFu+HIZz&xuI#@X>=4||95y| zLQ42TPk&}YH$_h|XJPRqtU-<}7CO z+T%ibPe6OEy@Gxby>T{csY@|b`1@K|K=5lZ!0qldl*M)q#043Oa0dL{0H*hDcL(4W zI4@s9ogEhcxBQxo-SU&sU@RHxiqx;7EGRQ=dwTaDRH%+t=!z=iTw3&{_ef1blQQAb zf*el(8rL`?n30{ZZ;qj@XB~6&y6kL`1}e!fnyED2yIk|1=4(7VW0nha&lm6 zj#aD9y-!qq*jV|KeQ05rFY=iNvkkH>hzkP?U0NwS4jOr1GZ5Bd*UEgNa1#jSVBLC! z{Xa)nw_ptL#5s&2&|oe&d9Ytp)@n2n%s5)hj)P*G6V&uNv20NuDpD2ufcJ}eUA`#f zpiaFWP~O%bXai6j=q{5}Lf_l`j}-ZOQehY3r?C{Ax|O8@nN$zu!~MRnHZ*~qZwmt6 zUK~@`^BKAT(p#c0N9^wHb0aPAA2f)33hoHUl*b#sHj<5G_vrU=(U5n8vzCVwLY?kX zxEb))ssf+|M5mqek0OPxqW_vDlEjn|$KZLOdCxKMZE9Le9@bB{NvkrBuhylm27xEK zvqt)xzTh>C;Hj!SIn+b~8Ji<9m!l`+3#7SK$b*~cE1{X0xBu`?Wd|DqQEkp;`WSK~ z(Ww1l>4??NAnaC7u3e`3e{yUXtmfq}%JxgGV{1=4ey7Ki|G}o;yK-6Y%7Xr?<+fGr zUyA?9shQM(lM-LoPx#~%W-v3hN@)Pzs5}BVw5z@v@7q-tPh)u+e}x{r;Y7H;TpXye zpbSM;$1K2N(!G8`_J;f}YerGkr)im3poQRhVwd8Nm|FvtW0|*Ud}X7F^gr`JVe`&A zD~mk|r;fxi^M2B>)C=Y!%G$E$HI97b%bqd89w!l;>usT_A@mI)f)T8E_yK@kJ{}1- zVnya4fG~X`vi5pV;H{L%1DJlp8G0fZABkMYVMWMJi}Z8Rl_6TAFC2wdYnl77-^rnb z_60-=-xSnS|H<93tu&JSb~GFXZNV9zk3eYTG3o|Po*J5IEB-Tq-n-C= zQt(LU)(#D+bK-6!lcU!0({ui1BIDi)C1Sps^!!C;ffTS>u8^MheU?GA+lKQg+<$+} z)&OO20T3r~sJ61OG%z$Mf6A{LSO(y8HO%3fCGT**i0JdY?MB!QGZLXG(va9)6E5Avvm^p8X!o%#lxs|k4@I&u%L(WBO+CX zR~bSQ+3w?`;P(j0Q8P4ifQy6dod2rjWLZ0my~MWsC#MI+t~uIhIH^7Pg~FT%&zE1* z8xHE?cZlg)*uF@08?)oSWpoPbYgNO#C5fwjOga9N;dav!nU|@4GC;||P|}-@nZT53 zT#3GWiVfGQMCku|&^1-|(0lt}KijqO5mrb7iN#ozdDGyVAW&@Pczbfe@D1RWmpIpd z8A0W~ihWpY(cf^oY7GPB zx4-68Hb(4t`tS!Lt0}VRps(&AU7f5FOG<<#> zkTe1CSl=Bh2rLW9k3NbdJ4rtPb#tqU*LNvwq#S-!E$I&i;BB7oyN=Efc(CfR1Z!vWt(J0{52%JVgE@|AN3lep}=Sw!ZqO`+JRm(6sKV)H`PK3eL>SNUP<`X7aTFvGmx$c3nyOsXDPiOELPeou~sPTXw670;}l)9GA~* z41<`DX<&pEA%;rPIdCbr68=%PN!LQ`)RKO3BQc&M{u%XUb6l-jtAP_MiX7FQBAcU^ zbxWQo77!8N#y}NWsP7io>_YCW21&lbLI00299XV{(r?fMZV!2?bz`7)9x3;WB383- zs3p;fQ$w=Z%L*XXQ_{R1_-+$QEu&%wg-<7Vq^|8j0$8wEY%|;m#(LI3hr@dhz6{GQ z^R`G3VX)-O!7~}T)!v@(9QO)B>oBE5vM)MSe2HQvcY5gH z8j7I!(X)a<2%_5k(7=fC)#wAS5=#1*z#-tkCmzcjELh;Hx2-Af#dvxThUuJAf@qUK zcpe*q=8yCSioEZ~(>1b}zH=+*1)82$q?}1#8uRh@Bs;a$I=0W1!V_0#Gz{tGHHV^i zP=EvOvqAnW&Gi171Nh7@jeF8n?q9xQIDQw3QT{FILywz)FH1+KPeeT>1T6~l(^wx5IZt5u00mm?(G z23bQE8Jm5VH2ihNBpn zuuD@s#A?K8s_csTCwgU6SL0ED=$pOjgIDv)QD~nnin1TyuS~#F2Kl|ZfUI2D1Pkn* zP4idWwE-quHru4nPjPmk2~HUdWGg{$P?fYKG;Y1^xG`@1Ft{EZK0nY6`R2hnVR0Lz z9>MT%H49S%%1$b_?X(xBm$k)0c;oAsTa6}q(F`z3Wk4-R@?*buNov$_Zy-k^`2bnl z35R>pU*o7({eYA|{ICHr1uVkN>qkjsCsCE8PmRf1p zT_l7Z06xp}TnyuH7AVnU^H%Q;gH?S843A9?K5)-`8lJK2mQW1Iu9N&3;`1%2oLzX0 zA9e?{$MTYSmdECFxT3AIcFX$=6M;LM+6CUn&(dYPQJ{uyc?0)Fx!j1MQo%gElfh%Z zuJT0NiGuU`(_W@Eq~TbZ7fj{yk{92aSq9HuW;oA_#%_UA=Oh~_;6%76AB0-mN?bX4 zvmAGx;oG+)LV&&*+_^b5%nN`EyEwtwpKKvwUEIO&@y>Xvt9_6aHhyq5#^Tll?5?u^ z3rYDuC<@P`IvT(U;n=Y%To@*P2)uMaaA-KgzEHk8T54QFnWxpWHFp5&wRCm>uF`$R zOk<1{O*K%_XNs>QBUY1~1t=c~A>I6wH-*6>Ho%TE8+e!e@Y`ojx8M=Sj*?}gyop^)>g)lQcr;Gr-{to@fB<4DXrS{@&^Nwk><*iXEZ4PwmZ;D#xi2FdHJs> zrb_)ty|BbxwDJZ?t2zj{@zV{tYr2vpoCYKBIWS4!p_ncQx-$Y|_Jhz_;k_vy^iDYj z9wp0gjKHy$$H8zbp(QDl5x`AMnBAydYvZwtrmxuq_{Dg8)d_hsbB9vSk|DQH%L^)I z9b;d8=(&&SYB#jHowg=JQ|ymMY@Nyr4<}aj9(wR?E6bfYFL?|;-5Wln+XARK-F+te z@_iq`Hl{1u2UP}~15@(a4of;V=zdfk3WJV;;yyMh9maelqA)5a9<4pLa%b!f=uQN3 zSn_&3X5G_lsD~Rq{bTdV^%#iIwn0y@B=Ac1g|JOu4BgsiV6)5+vTqzc31QE4HI2*5 z9w%I1N=sa9qGIRq$+fL7)`yu&Qb)PPwybwxB<-{kQ+G^MAtL9~iy4;|8Mw~7Pz9D~ z6eC@R`eXqzv#UxflSmJVY6fnnlg z8ox5Wp{QA=JG8)g#Fw0j9z5-$TRW3(&rFr+7B(I#C8J-hi!Vg_B(>`G+QI<8k2kUA zU(H6Cx>^$lD05otwU;`prH&JCIbtvwy!%%b>#RIe5|)OWs>s@LS#m`fML##w|*F zrObH(mZJjx&Bc-D>gSNDcFcAbFEmmoe5@#7o6$jS5*;A#e37Wo`#GSQkMJEnRVUGY{Ta!yvpeY8-%J zL4lB*rB;Wx;D6Vru*dP?`zN(4p_H%8)0Cp1WE0d9 zc5d06R+`eM=MJ27&@TXZA6W_BuT3pmyrT7lXp6`cVjHOLc0EndinXv5vXtQ$wNh9N z^(WUdKyp)czhBRBI=)Hgj#i-WSGghlXhHF0=RJ9|La2T|ZJ> zutChm8LH3is1tT`4Q9T0Iou3sN2DpZrZ_E@&nlA zSYMZ4+6n5FYIuU(EVSe1u`5v~V?nU~h#bgRK$+NfvhIIIl1-7pb#3au2`chR6D?89 zX**Eu-9RE5dv1ypPmzTFQ9jL0sEYQ);?knU9`1sGES*ii(E0S)*7fy==}Q0#S+&2E zb61rIT8DB^YKF@*6{L$!@V(C@FV2z0ePkrMnhl(0Z&_F+wMovL=3bd7(p zU^7xrU!kM(7D{;;%dm(Ll74|s`TCyi%cJ~KeZ7yZ4pz2I(6!AfG2g3uY!ug*ykEP)+s-NmP#Z<3R7@$sKD|UVIDl z6D>JfkLy0s0hd5dGzthy&+T?ROF#Pz&ujSDnqMs&*tv@{3C>={hH8KG;pxBAw?dYN zw7-Hrl}Cni8sfO$I2Mmvu9I1Ns-CGo{Q{>mg(#RV+?@NZ2fh5zP6jM+`g1>@A4yAL z=ZD0W$YKvS!W!^yI`MBnG^z+OAc<}PPm;*sO|RR(#GBNd9{F4fZ!qeso~pj~kd)Ce z{YQ=VU+`j}+q^`Ir+@$vNI;v$Ih1*F^TEjVGGL4p}k%g~6>4+QNo32|GYz!1trF4xx zQ4Tm|XrZk?r&h^84$D*ja0 zToMHS=s5xUvGFAC>~}BPray{Pyj7;*A#T2)YsRP>@ES=peo~S}bxr?I&aTC|WmIpf z8~hD*v>54gxvqSyx~o*XN9<&*w@yf#c{5_RkEgAoYDL{GX5YB*6Z~#|@kE&We*eYI z<^`zX6-TuSi}-ZYS~5_^#K5$Bp0+v$9(2rC9Ch_#Vse7w`@kss?Wn~6Ezmv=I+ejg z0Q45;_y!!Wm`q>Liz=8mcMD4&rv3Nqnb1Rn2> zohMTkXFHqLG$yJ)bC_e+WM$Dc@woS{N8pk_*clfpD!*N;Y${(`CQl08fVOux`F_)Vsz!mqy zcwY9ErXtPz7)ZiO5~2w1c^->h^aia}MPTi?L@!3IZwFue(6h%8>DI~C?(cGc+4w}~ zCMdXS#D1DqfjNuk1n#9@B#@gpw8k?m-ZO0E{(QBO>_H!WBA2jQ9*LSpw(o1o?nA6R z@9%>M%8*YxFt61{j(FAny50!BIgz|X`K1G8f%I#xe%5n0GuqJE__KE_=^S9F-4;aw zjSWLaxkcxFw3>s)V^gEQ;yH`oD?*F_`yPO54K>#A_iufe`ngeL+`ANEYwxujB`n(> z;F1kj*DR`#BLjxnRX;uX922|I3Sjr5Tyo~3bJ4KV_no^eKbBG!67ut?!YsYEGz&4A zWN?`=+CiCWZuVMn!#L%)lCwtAKb;NO8-6;U zSKw)xuXA*4DvRHT#ecM+zpd+Q0M!Uc1YkZt8&D{oK0&Je zBmN3fzG{?17s<$RzI;AOOYmoDQf&|BKAa>iKjqqRzud`8rcpgKhJBUm35iJ8#+% zRILjvEHmAp;E`-be7Gw{k6Mz_+Y`DoBlgNKH99B&H|3Sx!IyU(Q6(Kr^Ou&D8+`x1 zp)Zxs!#SpypWGuoc!Dhbf57*ReW3R~Nr4gD+nnH%toLLicXhf(w#3<@We?IFp}T+m za?YTpAyDWB@44#ZAJSNprvV_Kh5_O|`RdxsRpjpu;gU;)HjB16rH0qqnBG+h|SR?TcDgCncD~ zXm?H1mMu}Jt_@i~z<$_>v?YwUZ6t~5X0_>tIxb;{Ni2z*2}(maaN<^`>Pbj@4WJSx zURfjo+L2jFWHB{te)EfQ9bWr28?Kqkm~Si!%y1TRkBPF=h^LvC#U8wlPBm#&OM|&h zcmq&v8@Ts)00>K@HB=24E%Y=4^b3}j6rWVBPn0@<4o+m{V2|3VNqdAa7ue#Z@kLC3 zES_K$wfOPob`RV>)_V>~OzSmpjBnb`;hD)<*L?GoPQfV*Sb4&0bLhJ$1SrPu-U#sR zI$$KOb2YUH{{@nl_KJ>o4{P7lmgv8bm*9I>{z7b`sLFgs8O}h9*_&>!2 zOR6Y(ONcB&!sH2!SQV|`SYu$uDR`qngTnpT5xMOQ*2Q0S)4E^;<{7&wM@#|AS#0rez>oF{|4JKZLOW3_NFEkO(saVV9v! z9|yzT26$ZL(!>JwB5o6Q+klK3S$GF^)_j%>D066Lp*s!d!0i%NcnxEIon>8Mx!qA64nwr}fnVu^K7O^21Xy*_Vyl0Oic0T3w-Erf zlWj-e3QNL9WV(=+;N@+x_rB^Id>zg~jAA76{2|dJNGCz>Sl|pm?hCi-f`t#2&O$%M zc??$9fn8?p&yuKR-D&m=fys1LZ1O_w`w$}GdNVzq(y|#2kb7m9D{lenXjc^T9=#fB z-y5U0xtI^wv%!pYJKv~#+pCzdJs`J@efz@|N%igq5~R<~(3Exj?~feP0qoB0)X z!+F~|>yCqAyz%XF%Jwjjn5BBm4v~<_=6a+x@ZUIS633Ncd;fxj)?cX`kPTSF%qO}z z!rUUX*&_vF9{2OOi*Jn=!T_EDEb;^fYR^E_kFDb6iSaRLa{j>Sc16xu548_x62^Ji zW;^w|9q#g_fN##&>O8##Dx#{!_ItN`j8k|}gu!T3=lTowHSp(af;W!l940N`EO=^h z;M)WiF9rCgh(nZBU{|tOr`raXe3kZ(0U3~)yCi_R+kEoE?r{?xd2@8XVy`BqhPNyTD!$xP0l_?>a-0u6WC9epE}a_5x#Rv-fgp z2AMr1Ve){C=?=ZfKT(Jl0`1kXA7A6wHKt74!^K6bUmOF=v#w8HIy|hEK4$kPs7N-{ z2u?7o`IRWf<#%RsPZ2+sc5UQWYChLFX(YswT^riXUye~8am&wzdCt58)5G_A8TQvd z*e?NIcIYPXJW3lOB$0|*j)|J*@J!77 zQm5x0xGsTNg)}4Y?dxLIN{Z<}>yA(AfHN0@L#92uAp#Mkh4jM06CA^Us_5w_IX92) zazAVt{X3sxw7_Gz8vw@-O{lx{yASHmoM>n9Y$0=R+!@{G^$L;uzodQ(-(-NLzP_|u z`U@?di`;YNd`+Pv2oC7{F(m-bpSh}a;<%Jy+?c>3sAP~x0}_aV7rfNZ9EHq4UZ}YR zu$+yB_gd_gunsEO+V7Tf{cTrx< z_$&yZrjN_s<^}5`d!{WcqlR1SH5Lx9zoE&l98u*g6M7klrQiD_Dt}Bn20Us3H%r43 zpgGQg20bhvJ8|pI0TAAnM)&^>{_^F3FrH*JRF(Ow^hQ|MhJK6N1?JurOKj(MF_>6r zJY08VTBcMrUpKmjWfX3@WwgNpRP5~$bz;5Cf#av@_I6Vf=3O>1P*fVgPCdHPju(Q~ zu?KtaLL$%d){QB{Svlpa&ChLkn!a(MjgXreb$hJYS?pnYLP9zGWs{7iB~Hp)y+>|< z!lk*k9Jx<78ZtO7j84{ucHmF-g_T| z+#mg&PrFe@oW7&I+%&ZUeyY@aQ^X7Uwk(q#wrpkRQsxv*85z>TWj{4>2s&)9iQUs# z2bgwHrra@+%M?JZA70r11ZZ%nqF$yc@R-d)L zb+U+^z8NtI=0v4i+hgn3BI2S8tlO)E+t%EMucfZ3HH@SbeBdZ{9DdBlHhcqzisuc$ zQv5d4RCH>mvQS0-fa=3n0?Eac=IV32k=ds?d$3|=DD_6-U$eYjYZ7-Xat64Ag9SEn zV@M9QB?T@^E(kAUXK-X2jwJRT!TN|8*%9>~v*(ob#~{gHCaPq*5mUp&FGnGmh-*!1 z*atRnK?XDoGLzYoJkq$3|1i($rgMaT4U=^78EtQ*Uc%-_Pk??7ZTf{td@49d9giHc z#{bz#mC@joRixLAMCwNeB}y9^Ejx8|QyjWYBkJwQB-i)O3!dy3j#$g+AJ*CO!2~;O zRwyqfg)h5K>k2DM`d$Zc+`eqmx_bB<8T3%TN(gq_FM@G68voagga68X9i^hPoIvV) z5l3hjAp-~5Db;g8n&>r+V>)c17cno@+RjYx`XxA_k}H?pzw<0HHaWF_ z|J>4-_L)fFq${lCTnyxgG{iHbG{m!a^asg=v$&ok)8#RD;cFE~vm@2246%23EN9*s z&74Q>PU9K7?6_dV=66}#WS!o{*n16p2suMT|b1h?b20rPX-{HR(v9e0}3g+GSP~-D@hNH7*3>K(5lIDf=ME1M>fq zt(ah_mtiY~+iLD+r;;yUIsT32cN2C)%CP$JHDSd^E(cC96qLD(J&<1&OU%q2OI~mP zvZXs?y33F*<3XQ?cvf7@;B9E?z{y=`{(OY%6GaEDm7a=pr?wL;agLIjxBOjzo#HkBe^|7;gXK9aH!xYz{4HWaesKYcN4;SS-+-o~S%ppHuU9Eg+LYb5(gN z?AC$xu^&jxGle`cUEWSfq-0175NQCRXr=ZZtwViaBhA;OG$Suuk5X3wiVPeBH{Nc3 z$9kqv)w?6Z&;suS%w5K?t4O&_Z(*QoqjaPUwtPwnM7hxEDo1}1x2fX;vQ>^u2gHXm zJCX54F!IpH5gTk))7v%uNy_2VJRLWgFM{;!oi`Mz-NMA51QlRt6eF7lQ{0)(K6F)b z;uOEI!3YnZIKR+3PwCKf6LlZFI=mY&!$JM_m7W(zHD__X%_i>y2*fkeD_wMGd?EPr z#?;onxibMY6&?en z-$=vkrcVfb2+suAdTsk!Ts1K5YpIrC)Q4`9IK!Ney=HKk&QETKhCYNb+s{7*Z#z~w zmr&+wY5kwvJ<}hMwun6dUHEbk=kvp4*6rGuMW4-*q>t*>`%Rqs>I&;;RS|{mU@QQ4 zyH5spOTTLh?hW)5EL#hxp$6CHdZ5KW+kHOL4GH-+L9Zb@)!p`rKTm`7rjUS0?Py7O z&Pz5Ok?p_s2$^fZbR7=c#GF;exN2f+mVAzA2#1XaqaPi+sBus&8vc1LT>c6QnC}H) zrpD_eTcWC=Z5ET=1(7kbw23-p?GM0zyE=7Eh1xR@;`=oEIZW7uPWcoTfkd*aV8?m0AM_)EM7NtzxUGLrS>nd25c?bY}O zwPs5H$(1`&3IL?mc1g;9eEqe`LRMk5w6btk)oD24rxmV}ES(Y|X^`y#6o+S{I=Z4m zLgZY#f4gZN0E+M_@8r3i_#a(z4693Givz*;_>xtRlKn5_)`d@5KTEO0rZGT~yA-U! zm*7UF$yn`Q1$*?bxtAwUT*ri23Fb%hz|4BhzC`Qj;f@Hr&!<$BE}t>z3vVDvw$>XY z9zh;w8?8o43{)gbEtxD(hKqd&C2K$9%GrA3V?S>&qljO9K)KI>XI20EI#_7vu$bXE zQk>=3wrhGTx|PU;+Do=K`#N?r?8>4Zx=j>1XBM|6fGNuBwQcRkqMcz<=>#6==uiE}!B*5m;pLJDQwEnJL|E45Anns&N+4M&nK|COry+@^FR*zSt)^%dV7fM(|Tc zUB^&;1&0XxvboHud2pIA?gA_M2?IA4=Ukf!k*_!neL@6}2ZeDaYEq1~8|^n&abnc- z;nKSF)Y~c7LdWB;4XqsU;>TMp^TdPHWdJ2Jy-t-swNj})Rr*`KJ1@#Tz#p3 zq-Ak)wr8kzXT#+=fHG+}fg&XpI%Z{SjU#F$@4uFb(bMmnrw9jb?R+!-q2S~bz&LQw zY;sLcv*Aoas}%oDbtElj-#5a)G^mT$hb^j1wFV_)sw4=x(?-fHDNW{5Xp&6V*EM z)VzI8t{X>rtvqe|eHmO0lrC7{ZIg4{;urceFxeEY8L;v8*rh$h+|zMh)u}mYb}TSJ zn~N#0tqc#N)^nXfg(x@M3W)~e@xw)LaDO3kPePd*y!gx!=A7TI(M@VY@uvWKg(@V) zxJ!9J5xh^6UY;WC(XYU^seyg*!!#v6P&D<5B$1B{@V}hsKDaV)k#G9#&d(5urYIwHJ!MQx@PRa-ubwg= zk!kb1u#7#C(LXs1jbBu*%qXjLr?VmRZ-+#m8zbSQ6Ma}-@dzgWz>^HH&F_3^Gf|_; zX6YM3ivFIMguc=J$Rc4|=$lNN=a#YfYFE>A)F-9fQa3~WTgTk*5sY#O&5-~uGjQ>) z^(>4;08Ut>+WV!!`m{M8@WV1f>)?L|S3qnu=@_C}`N6u;c6C1{A>}Ng6Ck*w|D< zGmTr&s}gv{UPrwkHHGvUwAeDl(=oG5WVj82L7h{BoR(r+!`<*0`A=3|-~zpSKg8k$ zQ9cRz9A&sVZt_x1$`w^CYhS$ssA{x?hH0~IHITmSj_Gf8*b`QI11w{;5-Rdf8)*7h zu-I|aMYaD+OAIx)lPwWv<;qqQnDsi0PP!aK4DLQ7wm|jK z+LQP`{lG;=@4L5=kgs?ZO9RI`}_ncoxpfF12jSdQAx_9b7S-dD~_a~+r?-CPn z?%X`cZzb!i2Hl?GwqX5+(cL_eA`n>&3tysLDzo2p6owW4zku1KQ}byRX_=4BpiMBe zsb>*Yo{$waRR9XJtHUba`P>DYVd}bE57@DV+ZIY5>~y=?IuF(|Hp{XUz!-)cvYWw>J^7Dn z;vIz(^rloUWS&-iQ;em9oVh2Y`gY1FMuSzZpSJRqCb!bWdcPgdP3>n5m7sH?pUQr} zLFu-}N zz8r3Ck1f*()))tpqMBDUUMi4feP1@320U^GXw%7*#2M$cod<8H&{MXTHCZ+nZe0N4 zq_65F?^7QDWb8xr)Tfkv}y6E&QZ zyTBQeH!!{1)bEgdVd}Z{ScjRLSU-oAoQVp6iU0k}8{P?hcYeK_F&7VQ(FH*gn)qo^ z(o}32v%md(p`n*-NMGF8lEH)LX&Iaz%nVdm0)yx0?3zTI8nJ{k*MX0aqTY=SAkv-l zb9}GuDIIwueRX3dO0WuhMV#SE$B=SZM(y=0I#Q0nb>=cv+_@8wL@nkU`KT9UY%I>+ zKfG~@G$tFi-k@lNzoMJ)k%nz{P^T^3`~z&Es2XY3a?v5cJs{Fw@`614T%E;v6&q_T zJmbPs)}wTs??v*N(@z1;=AGf3?ktK4MDsySEqxB%{-hBj%$qJOZvUzUu}Yy}EMc#| zbeG6cBwH%kPJOQue`ZTF%MfPg&>H}^!Bj5oLqUS;x`?X9XN}L?TA=uGzE3NxKscaj zx4(Iu!(yG5U%hXdvmr)I<29`G83`)~yHiFFxL@zN2AUA{RFd=>59l47x+H3qfN$DM}nhasur=5mwx zd3$F*4Ml?RH27cSn*1J;T!tX50kwOz8xMe=FTFC8nh8$+AK*^I*}n|GXJOzdgll=+ zy0G_V?3c}ch=F%ZDc#5asNb#-o(`*3LRb0SAsg8IAVTN(Hjw8a^R<{1a+euu^;aa| z(5tFkm6-0eYt*=yc|D`;e3j-@(!lnjSnLlEIe|%k;6CsZ8_Ie6!R{|w`am$sSG$Qo z$zA*!mT6sE5E=dT$^L9H7}*k3)i&5m)&-=msUw%zgShXlIsb#ink7^PZ3wD_#=@$-9~$_DCp0|VcWPLs=Y@23`ZjWB#k3gOh^mW7nvcqQqK`aY*cWOoGx1p9l$Nc2*`VHJsfPSjJAWvy!K+V^!Kb?Z+o~dIj{jq8@z3;)_HLu zBsP*xtDu;${Yo$3WV5x?wGfYm`QN?`j#@-xJ<{(cLnY9WSFfFWS6#v!V^Yz@X0qby zwt%37eyWs{jif#M(F$3x8$e~QI5zuz7ns66FDZcOUQu<+g5crp&+<&XPeMaiK~5<; zhbi0Q9c%R1>`5&K8EbmV_BCrjU+74dZ6wg_O(PC}e6GG9qo)`DrUq{r4l>ig+$xpg zsyZ>=L`Ohbb_+WQ@UbmB0~C!uDOE1MO}V+15%ignOFc~T0ZT?y`iI-vDZw-%PK{HHHB^Nc>CUhUUdWjoLunZ!|>Gn3a z3}?%`nEJ0zRt8iuz2iWmn+D{AXPym`Wxp$+1>!kJ>g}#A>BLppVK6DI$^mVRtkjkQ za-+eCTYYaJ#Xb7<>QO%5)$%*%#jX z@HXt<-nPfE3X-yHD?(Uh_D{Kv9bz?jqth@+=ncyZOiPp?gaaqTwvH=ghER_jP?b|Y zAEp4tcSAzN8DZO4MLxNl6YoV>7E)ddkRJA$99XF+L7#J+j*0(E^^O)dzez+H^Lc*Z z)89MY48EXBzy<%VGX5LxJ+$ziVR&lptL9HOD;N7yz6@)R?idr~%%Wm>l4A`<>2p+bxWJ>`>*q30L)Y0W!ybD z8^yQz9`q9`FyL$1inTv5nq(6Azv~ka>M330SJQu;1(PjV_3^-*$aF)9HzYL~YPHMO%<1Q{2xoOF8X*cI zbF0#RE_E0J&2SEuy{xPaZnQ5U%h7i7AM3X^hAY-d@C3AOEn^J=eLmo(x7r3pw?!CN z7l@~yK76Krb~ixIO1)caAWv`ALcT#Yubi)!fbuN3nj}oGM&UlM+47e@OqzmUicIJO z!(6W++kUFi#^K&Il&&@lV6n!N%g4`Jx}69lh>)GOah7Gmr&#H9hlvg#x%r=5hxL>Z8iY>u8u_P|Vv8W6Nwvb{ z6ZmvREg^LEk#N=1bBm_{kHE-&GcSHL(yT>4@v(X#LM%M@#+R?LCvqr@EP@-S$K{*_ zA8&Ay!pKw~13bCquH3llq^^7MlrF1FDI}>Nx2z>;=9+aG=c_t|OaT3;w&swf!!c8_ zc4gu-2<8}}QJVjcxLR?{1jP3CY7Lo+qFvs~Q3F-h==8FF8upiVt+BP+gs)o+>PUdh z$RZ3bWf-+yMO~w+k5^Pn90@Ey@3Veo%iI4oBvF51nh>*Zn9zj3j%_7H+(4}D>cTnC z=POSBC#TY`Iqat(nhS}q1&3~fK7lKa-(7WSxQRe&6;lt(K;bB;%Oc=8e~ckF6h4CH z7`#EW4v8v3QK;w9lyYg-Oz`Iq<=R3{ZQ}+Jv8{^8SyLpq_$o|{BPZj~ja1O>y;YoXkh)T40k zwkU6Y!6{52^wIOiidF04i~nwAT4SL1ApAz1;q^!GbW%vIHT??P>C79d6QWJa!1@z$ zAt4aO))V34W|Tn=rDfzXaDy@oQMn$|e}Wx4s2`QV*6xuA@2#|>*W^uLyDGo61$`Qj zRYpWg=~;t-WsiGCn9KGdJuq|RI?w-|1w&QqyXrgrKep5NGd7`SpIBS+)>t}%K}&NB zPFlU{x!1FRbsfzq!M6@WnS9ZzpL?C;Psm#C^@2u9r~1L~JZ06=xY21ugKx{a-_Y#u z?7O!I&SH%%Xa>V#+#W{~z<#R3Ckp0odlE;@%v>eA1S-t3ghu?Grh7q@=!n>5Qso?g4dbw%WTSi=7k0kEeaeX)kkT`= z!6i^vG}<>}VQ>Ag;fSz|6bY6ky+L4QREl0YGSqrf7bUv>nl}LoZ7#As0&+c?RG3ulD;;pJux7I@#^4O}^ zy~Thbxo)R)ZlPOBG|xW;S{reZ_yK@J1t6r`+YnxhtId&tkImGNO$D&TrCw#A<&Uy0 zpJkioG8GYXu&Q+t#gbD1U}&xOthq2{pJ)EGZme#MKfiKpSbz!)@a3>^IE#+NLoF%S zvoAKaK2e!^?v*uxWd(S$h%MFC5M^eP`EOa#Uf!}115++bB8O(SFY1sZZx7CT%FmRu zvafaaa|A~0D$4O(SEKPzm~2nRN1E(lh*~nAHPwJ#hiXH9wxB!e_SxSpN;xbYr;FxKAKq#iKhUHtLN z{EtZI`xaP6-OhiJt4=~6OIkdPkoumY8l9+|afyEIt7k+FiVRM2D2D3i8tGs0wg2-T zYFG`&@FzBjV9HU9ZW#D?Y?g%VT~7R&Q-3b?<-eJ$r*@v3FnVlQtNsz6_IaQ=N5udf z08dC&ywT|GkHJvKR;_-avMk6F_+f4TkRMRPqq@xwAn|Vd=kg?t)U+2V}{~K zfI9K(!^Tuh5xgr>Gc0DFo2A2&I1zHPiUSq`ixeUM$I+F?GvWV#9r}E_KOOi+^7*7F zXYNAQMULd$+*Y~Awvf54_)v89BCLSS87Q4H>iCIkq`swBz%8`~A^BJ(TTz zyxyyg~LAevkIpO{5^2Dh%LyJ!6w3>(^BTv7yz_0a})GN89!Ke<0-?Av7 z2Yrg&xm67i=3DMy0yG?ziAlu<_)nrxzmgzL%(A9ALC zGKvz5RzxvAnBrQ%-OgF!?RxQBlZ<0B(!GS8*PW@}?os=5e2>Y0U_V?InApQ48Uo>?7u7ySQaM^?=t-uo zMGPhld9)mkx`U`CUyA%!Vob-LN9f%BJQ3CM#sV z@Ps0G#kH~p39%1dQmJ&us?AdFs;shUL*WO~v8g01-JI5W*5waGnS`1)_PNuXV^VFX z#M50?>ya$l(9luqXQ0+bBw@ij`_X6ZwSkn>)kPKVdu*s(kcoC;ks{gzXe6AF8wNof zcVPpMon`>w+Zrtp?x?}JPITG|MisnKF>RKvsdH{UOXlfOc?vO&iZb1=!JNGzdTmZ> zjmo)wXM9Omv7_yH`u*G~`Dk~WFE8VSgHRvMEQ&R?G3E`HXlKx`A8zuxvYW4X6R}@z znF{&L#3Wd~(a&(Gl4EX(8J>^B-^-2{cEU>DX6b~+;wf{8a|ucp6MpDng9Z{T)g6a} zX0Ktl#N;#lB}s1hY9qHRKp>~J3Mcn=`oJm2w_@}u^G497$$Iz$1sa3UR+>D$?C;y~ z&6K(K#=$CB43phtEC%z@765s*=mz@b4z_Tuum6=!kKL?L@~MT|?L!XUyWuPqwWKy~ zT2UfQE%nhZ5?HjfGIkxSiaJrO$;cVk;Zc=Ed{ml{vQ;@E;!j^qOCr{Ooc zA6}J(e4P}`GVD-VFIAKFzIMu&X+3FLEBfl_hw-nVuPLA#bUw^~i2-U?3&kn7lTUw? zi^WbkNIQTuC9nFdpvBBO`PChW?wr99>_jo)%OW!pANp4H8o^4v0P?$r^tM)A*bm{3 ztd-qwu1lP|@e^o=*7kiZd4nmHi{7v6Atflv!~Cz|-*`%wRAyGgzWG#i)4Gi$;}mWG zACNBuD-%yA|056%?y1>f`82gA12jij)l%Rx(Q>i@08q&~aY%#m+;7K2#oFTz^`w?>`YOvw5Rp zTt)7~PObs#s-HXiC@}4@Pw$F%$}iDuLH`d{Iz0Xen~E_1g!!SUBYbvUTY64zqGD8V zVO))GZpFqxl#Q!WX8=a(;G8JB9%w4U?j3_YCo7G!!0#_(dPM@@mVkx7ZgoS8R{w)v zJDWMrc*w+L5J$=|j?e@n#{UEC)Q#%u@7K1IvgdRwdsRF6w#@VELm;6P?`r=vPG$Eg z9&rG``kYr|K2fx{et^xTV6iMHIVV==qK`&rgVl2W_+If2W(Bgk82@$?h=UB7Y)VrS zPL;u~Hu@oH?H^j1gL-xXx&$WxxK>+(r&?CH=dLqr@(5id4#n=afYKS40k1M@-orA= zS!Sw4wZlo}ijXA|U4C`_#%HyU$Q@>UN??FP8U7z=o93RQ@_p8t;aG-H0h>+1aMB7L zbi`&9E%)j{9YRVJ64^TZeMM;1##|lXlb0=}vTv?;)pAd$tE?#`l+3FGI=6LbFeDJW z>K-2)a78FxyG!ETQnw!O`Va}MM+8AB{g~em6vB%R`R-C6$P`Hp+Div|LY1;f&2!)t z4J+GzcKJK5xFkWkCohFu!T=zz9Ix?s8vz|L_O0y=6rkZ`m0qvT{^E_5CM+5%*Bk(< z!`Dtk{#(}jwj2)-&k5$^d~lPljiitrjxgDTW9=>CkzLqE+Ae*>Hb9VbyOm;jZ=Qnl z`obq^3j#2f)`T+87HNWTL)1P!dx^UkS6kdf!2EkAh$1lVrAMXIh#JhZ@4O zTMzVo4NFWH;0iWN*M*fO+_ZP}XhyT6=nlxWQ+N;d6I5O4U3WIdgd6V4Gq1V+pB z=u}9400NfQHA!Fp(_UxpfljPr!sJZQ*HgYHSgxl0!~-PGq-jiLcH9Z2cwv_>sXSO0 z)^bP}u)7rlxuE>JzTGTjPBN@NcgizOa(AW{5nsogLnBhm*OQI5W#&M)rbavA>6q~M zHZExWq>A#$4wCoaamzgU*}7!lCEFR=LA9jd2ajdW2y(A%m+6RJE{o{poHqhv0=AZj z?4@5|{cPNkln`Yh3({o>k}e)Cw53=<1aS0|WCR=5D%h7tDdy`Z3T#H^AOI=QT)Nk| zizhMTLNssQ$yiZ*=~gs2iYl* zY1t&P7YMyU7vO1{)gCZ3H=|T(9_o_ym>AY0l_r?E;RzL97;1KmB+RT9w4oftUGPL~ z0)?P6nH#62Xvpy2bP6>3Ja35p9I7U&G2e}&7noxDW zkR_QwoHfl=O;V~-NZdMLC!zCMFI&~rc5uEv(qUviRYm*)bqn`XD6@sOT$#weT8!U& zqAESiw7i_jLZO@P^h+y+O)omZ?-C`_SZlRH#CyWs2K%I8lM}vRgL+9hq!so1gTmeA zL%MCJ{rwUHRC&tRZ<&{TW2mBz*=@PesXS$~(*Z_x6L3KZf*_rkuJe{Fp(^ZzfC4yT zsPfWK(G6N4i@lFl^8v*m7^&rJ{96r>(LK_ofXN z#4^k~V!UyFYl+pdA$x%xuz}B?|I|3ZR2od6Z zSpVFSq229uSWIF*LZqe++hoMK38jWKU0|Hu$g7^1YVu|XhirLvr6o$B6MqdP!G6gy z>7oeyMKE&m;50l|QE}S3D0KWiba_UR3Bo*~t;Tj2B(1Z5VJzX&*Y^%Om@;VT1-QmU zA(uCFSY?v(B5!|4uW3~Og5~zp^d5SXB#`=!`ZbHBwpvD(di|>z+QGPiw-n9()G(Mz zeuV2PN`D2OHIK5~M%UcmVteY*-iTmOs_w$Mx-SM=IJL2#mma%M*!saAI^oz$yJ~WJ z!fQpWgx}dm5V2b?fwd_M7YBvkmuO@_B#)#}6M=zZs9I%{$iYWaNq>VcXG%W8WRyxC zBR?kY8?_e#eAbP;8jIjlnxRkXrfM2HpX&om+Ac(n{zgQfDB-igFJ|o_|AzRs)3yQT zvuig2@Zq3b!ab%Sd7%A($&d~-gbj)^-dqXns`oDFE#wo>UM`b3Q`_Bw^0%sG>Ku^( z)ZAUH#B?pW{;}E8#xJiUR~w>V2VcFg8)J)Z+>lA<0G>0NZk?zu$GP@Ly0ER=7>8w) zIZ59fbP5-3717GrTnPs1DvA6@SUm67gib^oqVKx=JEz3S_m^AiyS!t-(@zdMNW3kh zrQ`28KkIl5lsDKRxg&}a)~2-FpU!}^5u;5fm`xo1gOrnop6%2n^GwT`zs2Cu z(#P%zX42KEtBSX9#2ZrKStVT=bsoZXTD+v<^fzyiB_ziko@5-^2BW*ZHDsP8-e%+I z{_jq0lK&ukxp_(2J40I7<;@)V6d(YFEF5T={*h|H;U6H3wO}Yw?H&P%z<&%h5|~h$wTnt6r^d5L(ME(1-zye zezg_i>fl+}GRA0YhNo_0hred|gJRlN#)F2IYn>=i2g#Zj5iE3DdXR7X)IrL_ejhIR zU~a0TG0d^XZAw*Q0d!BjB1uOZ2lU}yaDLeP<)%ZYYNg^_l^V77RU~pVK-s)g1e>Ar z+Sa9SPR@ePUhs0l4$01Y5iZtv-E;Z;2O`;M8#_IX6?WUQA{eSLU(T%%t~FW?^o%1|m7xtaD>ME?QVm+{-%0B5tyhU)sgPsN z;}geL-ld0{dm33x+NGBW^&AzV@4mB8h41Qo&lW5PA7EnahTtHZ@Ib)zzBHI(3&zG= z7`Jy&=7 zZvLvGbN^)b><{2=&1E+-z{(E6h2nPqHeQPjI(mZAz^69E+y`5@o8fYLm=t!p{CEA6 zDd8_tqQWpHKWK6^sj#NHAB`PNG)cAJ>COkoh$p3&nR^j#*4#>g4)GU4-rCG8{B&mAKN!C7v)9vSI|vL6fa$@4%r`SOau3*?enEzvg69Z=Qgp0-R? zeLGNH4R!%X(U2RlF-6D0|KiJ^9qWLFNNk~%CFMW@e!h)$YRcq~-|*<;eAexC}O4GhD^80yD-RJkjkdB4aWBNMyTYb(k4=_ML?;Pk1SJT9` zqYgG=_E;p10}nRZK!uOfw^H(W&>ZnRjk>Dv!4RDFoQ9|700;wRsKQnmi9JHeXE357 zSD%sl`>-8N|Ae6Icw50%`0^5f0kcwP!OdM#_l2C=(mtn+85w+!?KRg4s}$-FMJid) zHQ9|mQ`+_3%-f_sC^b5q0RB;;mgNiEy1D?Bpnf!fDkA-l^a}Pp-(pNLG(V&mlN+tL zX-;Amg0vi}v?kI-@~XwBG-XAgcUZLc4y^3OTcIyX0$N8l6Y>$m+$fC?4RNShSWGVX z9HGbS&8^p6`six+r%qKUZwh#)JfZMSO!d%q@^V#(h~Uhp#WkS5Y}-h^9Ni-{(L`_$#E%7Ol|xC0)H&FqXwU54_^S%BKE|uqtVk z8IxEyi1I+|D*g-p8?xPfLWE+@z2u)^4Ykx?>&igPTG=6NqcY)9_#yaNSGs`7Fh8+_ zfHQn%k#3WiDOG2E@KdO-g3g371JGbn9ZATD>&4pdV#>C#z?fsL*C%)u1g(#lkt^rt z^8a@~v}n7Gvc($RIo0pA22~9FT2P(bg7mO?K`MT{b5d6iat6^5iC=1-op&50~xZ#)E;4*<4p(PZwUGJWSyRuKc3$l*`bW|uXo0BLi$vaa5#X`{2#z^AieP@>Tf zv?ZQ*ru_*K=LQh8Ge0*C*V6oxDC2m>>bcp&x*%J2Rx)(qP9YWj%FXC$ayW@h{1a|)v zY^P!4;xxIuGS;r|_%-oSDTOrVq5>+HAYWIR|3w%KDM|2bJ}+k`a5A05dAeYegRrqR z=)#qMhY5m&%(U!)E{X#OI*8_CSVdk#f&Ps zJhIHj`T<}CMZ7UJu>qf<>HiXngE9J-A=Vk5MNKLY6w!>k>ZZu`NZVn9HX}w~-9@ZT za^!qGVoov0I_X3Nb=2Ch7c~1-c~JUdN{E|vIJVlmw-7ujgf(_1@J!;s({gbkcAuC0 zy6=aVh4P?jdT(ufz?W3Cj+1(k@p;?BY35z)8XrevPT;+|*L^+BPquI|y4cVxr2OX9 zuU{2+8&j8AIJvLd3%o?ouBzLPdIaVH!E*%Fs&DymAEyC%yXC>TMK(dm>AWsyU9EE# zs6CcJJ-=E5BT2j`^7L1Hc6B9BuPp9?9qQXAahIE_K(RCk^v|wD^-pNn347Od4#fkK zB=U1b#4uRS(u1eEv+FN((6a7^3RO4pH#-l7fww!T)Z_4{lVT6jNBgtV!8Uo6#iL?J zKZCq${B^6KyEex;9J5mH#G@UzTH{x}>EHv=XpXu|cZ@b@aoHL4L_$Xdi}3`rhq8J5 zZkIZ@@DWU)d2O4N#odvarQ8^0U%o&EoL=Nr9hC>}KziJAkDcX?GAz)FYDgqHfD`La zrN6&wpzUFap?w%_UH@l{A}GS`KJTr=ip8o5MQ^8{dskS>T+z+0{ceCBF9QQ=7rFL~ z;EW`xtpXRCXe41|E%`Wr%UQ$?RI&T`%U3e4=u2zUCB=;ZAotr3t0# z8=c4An+caH7R@U6FJ7wP*4CR-Cyes&8vE08WMqJ?vwnMek^zT{8_$d!heYW(V?z;g z4r=SIYhdB7>leBPjf~3xlgL14GxGcsAKugT50$G}v4iR!RVrXd5s&}zi9-oKxiDKS zHQRWvs2pWi0Z--nIOt?nkAGm)g!PF+h)4$CHnM8fCNwf2k3ljRuc4SDjFaa?3aJQ>vFa9+UHTn-$TB6q94GPO5cm_e{C zq6Fw@uF~C%m!ocv3fBe%@7jmWnG@qQk+}v1`#;c|QKsm(?i+}d<@qYG&QENH)nu%7 zYvm^Zf6N_BH|NJ`Yr|L@}T3DlWVNIPGxdYCuWPr z?Kp?29BAy60+s&@f#nABp(kz#a*;Zn+YL3?kEL?6*%d99AuHmgV@ji?l!$*TfsePA zxROC6zOB=W|Td}OQRK`Fj-=Ba4*#iauqZQVdy)sW09N}yLC7-uaE zyenVo->l>!Mp9&~)~!hAAuLPLkhv7}5%2BakFh_@V5u*zNrCcEAvbHzqjdNAi57Gh z_$Z#)>mWs?C2ct8rWHCzFd3SA6xvf6Kugg|Y2d4uE5Li=uhMOND53q}L& z-_{)q*W87gAbLN67T3kx1eShPJ9o6&nEFtGo%g4>STEq)g!(KUzdIGRDBViY~5%J{UP9xd` z^ZcHR%8jqEFVH+K-38fMbrhP57-(Ockq6?t|BQ`fJ}HC&?f}fW4Fn?STh@bkr$5C= zgCpFy^}lFy@U>crj@z3L@dMGWmkrCD7z>gbuh4n!=1mq-utW{oPUQAp*Itc9{pfzB zb5dmPwI2^ikuADV+&)=M3RNddLc_xZoJqzV4?6P-BU1!d^`7;2<%Cedr44fl-%ylf z24P5HM@t<{vwMOqjasH(@jJObt8MjT5M_1!-7R`6wMK?v8dLMmk73~{ z6_{GgHm~=}dl33OWOuF<3O1D?wU6=4g1%gLKC}GsxEp$^05!*4*XcHzg*vktcRdd@ z=B7QC68M}!nr=U_7RS?W^VBQCQ$W2+pJ^bEG;>gQ2+`oWF3?xUngRlZmJ`vk!nt(0C^~a z&5%99T#$ctd%MsQuI-X^67j5RZw-7SbX@>{8Q5ubti z$B)`w2;>c?7)KLNUw}&SN+N669vUO@VzLOLcHKXi0cDk+W1e-R;9wO-qieD)6 zX}6LYD1C+zdl+uwe}V6k^jj2`%ACWh)fHj-C1_dmIwOuHQfcyKgQE>|W*Bx+A`+xBK7SVU zfuQ>PP{Iwpz%UyrL1kvzm4hlkt%A1e>^D1t>RTz&pw)mjLd4BjxyLGH-j4I%uU=rRf%GJx zu}X<3pTW9zaQ-OAYED@LoE{Y>K}1o9XJ$Um$jMF;(8T~cTLhgU=QEbORb@IsL*`)) zQ<^U7lY~DD{2j3wz%eibJ`mp;#wV)2ZLUTAw%j9b3csux7W{4eL87wcW9fNWOtFwf zv1zR0%cVYSJa+Anhji6lm}YtVU6=T4ho;M9wl)+#2!HpV^C7cQg$c~Sh*f|dd4kH@ zZ@{(45{llX!&2I%%OYw<7ez3G<2H>+V;q~P$R=-?;)t)Ml|m)K6emHVSI!-x;s0K+ z-W&h7Ymtvw5+zpb86e7sxLpIM^5b*8*awv-8|Q&7%~?Ke*af&p1uhv0n#h*B$g@2c zJ6gk$B>)#6Jg+G-ob;avFm(a%;XkM{Qa0zN%IwtReJu}p2#AW7aK}E)BlGPro4GcS zNdh@Zuc=6yjDohG-hU!vMhsZQHvtSsD1*&%L9z(1Zlm?>X-sD%$pSNxxF!n`DzE!? zT2{!;YmO@lGqK#`4otZLB>pxi_Xf?GY+AFa@s+VVzP2#XO=YSWp$x$ANIq?GJTa}< z{!8RxvpJ;en_X~k)XNUqeJ6u&E`Ptv1YB!wvK^t-P|m>l?$C|xigR(==;Nl;7F~^tJ7q=_ zVS|~BznbR&Tu(b9I}Kyzv?RTt*5{RD{W70VEr&nIYVqQxrV9#TwkCcR2G}VV;B2HY z$h)C>;26NA9yr^)DvoP4@6Z}q5l%WZJC;xUeV|@@{T4Gc^A!d`89wKd`&**Z;+mGz@^)(%S?3TW_B>jskZ}%!{205A=H12bAfqv43eiaI zx?CTH8eE-jw)#)f@D*f!y@&9k&+a6$+hm<;`b>T82RO$f7(_litPpz?@PFR4PJJ%{ zmov>u`#%xEetb49t;IHRH>Apd2^?A|!TkNc3NnY8->AONtOlf~w$rZ2?eq>l`pP-q zWtyxI_!{I~f3Yu8&D@UE?LQkY6>Y_}aa8;=_g?g;?+RdrvoT z>2rvDU#Z%vZ0*jJW|y3h+4kCml7Kow^~0=-niz=_&OgtyGKjA)_(%@U2|eCL0gj~&wHvC(49jlx`j^0+$SbudrmA2w z4z^)&@XJ7XW>jVZi*I$ON*3GD(QP?_kPu23n#e|KpQY-V1Z}2*Tqmf^r_XUiLz$yI zXQUSTvqczAX9I;w0`~KDG+JCm#ut0!y90L9ah6#5mk;+iC(-UjH|iznRR%~{@aYY! z!&QYZ{<tADWlp1@Nc|PFR z=0sUXgXUK#=ye_JzHvT*+ah7gTpysbq_L~a%o5^O*?XTrrLe?|5}g%6g#?-(nubrl zH6edp=jktjceTq;*pU+6Hyo2YKnRp<`v{r?3I+nTdobkKgC+n*!`IfV{_$dC#z9G| z(-&B~5#&MKY4fhjG|##RD&of#;GFC$nb`L}^!)rs!P)7zvi2#$OhTgp zR``V+lhTmeHhrGVQU^q{HTie9_Wz22h+d?^aM0KK{F+b+$;6lUUSbbV7d3?k4X5kB zu6kx)S7*4LfmRO2{?zkL9nx3GB&~|IHuMU<)_U535&S%2K!bf--t8$FSO96ATUX)- zs-&wd zR2%eR(?1}w%46D_biXCO>7W7;pd?kOg=3-UN&I}Olfq^g4hax=mDaTKsPkJWMxRRy z&Z(q(?$*m5I{||lR_eqLsIAIIYDFISJvP-x#piA7I@nv*D#0wZ~$V%?57BFGb(cJro7o^RX=N8Y*< zLz#_r3UWsjNb)sT)pb&@5-7P@0bPB-@tlijVwc9@rZGxfr;4+U>}EiYvnPe}l6jM6BpyCbDna@p7dDbVmX1#o^88 z=Xrji%1S+Rqk*76`{;oGxfNt_7-7s2loT=flr(JZSslUJP?mQ7q+W^b`mbRIUt`<6 z;a}#xhwGQ)q$NIOrdBWaYwjOS;mDQ$1nIx^$Q8Gh;JdU6kDHa>znf9~tdyEjoXy|} z;-XE2%u40U{M6-cQa1QX0pTVjP+5J9TC$U#Qhl=iQ}5=IE^?TY5z!f64w=Yzy63Zb zDZ+5&4~LbWID_I$LiQI+bx!ORY&eq$`I7O zT4pL8a>9InPbU^lsUGu|q?N9OL|xrKgy|q9bX71X=uFIqs7~}lCy4{GaR3A_F^BL@ z&mU4vBpN;Y!z%bXH~1_>*y#{oew9|f*19WfWrTs9>$I8fw?`N z!@pVBp&l`d72>g)uH`$c0AHz^uJx+JpL>7|ylW8!2o5<~CnJ-kW+ZtiU zG6DiI6Yo!Zy`cnAUpoLgkG{Yw&ZzuS8=Ai_m9WX`;-zo-G(SQV-UoVp3@goNwJ(8s z;*q z1-t8F&B&7b8x&Bx^Y+#HtE!#>a+G9bDb@dI7`e){~qju{NVX_*EJ~dHz$UlAG$ir!TwXx7qC&#xxsO-W4#W8Q$#9h;@Jc6_D^^i83*H-b3<(lj-PHg=*qK zf{*oS6QmNH-OLfBJ?&U6i?2>r2P;Ic{bzMw)dOr$={H+!uMU!E^xIrdVROWT2Cg%P zXo&u^!BfUJ8hj5ViJkYX0RA$wgLS;8=0A}U<0R^)BiP@=y58bfZEi*{0P{0jsD(h( zHz{+ZeR9?WLXYP{VXtpYCV# z>(F#T&d>>^<2nKkC%E6%2nxDF#E(Hz-k$pLoWRlcS0g`#-k zmn3Y%G6iRL?0$|(L=}pouw&c_2IBp->L0=*69psNh)|+p{du1QQ5((cD16%Q+2*fi zf-7tpVOV(=;o2#^+|zA9+YKQ;DFIq=A05k0LifJ7a6pCAKx@}8gHXs@-hWq&9OLd6 zt`U74+KbweF`}P)1v9Cbp)3E~{U({8JOMF++otJhUXkvL>$*Wi?-2i3GPnWYp)_T^-V5tj|;Sr)|7O zF!iv2t|N*D0*illax5b{!!X-1r zf%%T!U04#OPh52y8_Wi6sQ*NgERKURRV$Oijp*@Nq&OwF3xR$?=7S~!&qAIpp>8iw ztuHNqSw1SiqY>qfu9L~-Sc*nxPSzcvU@69U#iP`98@IQ3e$r8HW{GdiXnLwe7EsNT zwf7op0}U@^(AYYwM36l<%RXpHTE+cH?iOzBHV&pAlAlQljAW+z5H!1h8)Sr9q1Sl> z5E5gw-DW`cSo**20rIJx7EL9i10(|%culQmr;FFG@1;IMssf0yxl0!5#5yp(9s}3K znsjy4TS?Z6tY1CI#XeN0opECe6;iqs93P7Xmx2GU$vTu70#q}cx-e12NsT?!mTTgT z)9c5fZ>+al5ZRw`0iEqdbP0?BLiD(UO18@fSW&{yOWQ(ET(d(8kEZZ$185Ogn)tGg z{U;KLG$xyN_Mu9}$1nA4cz~_U`S9H0H6GZei<``&P&c&>m3;63KoMw4htKKUCQ`u| z<>{%?zk{##n(C=I=2Y=JQvtqAHuziwm1Sw40q1C`FoqP$&FZqd6WK&#veoSYP`*6w z6ZME63+@0QKZJSF?cW;~TSvRiHcLmVK7fD~_Pp+p+P^@;@bUi!Wg1Rp34mPF01He= zGY3MmrGTU;>(*#|GtY7_z*nRMLnw~G1$)s1@gBFP+5-;+s*Wj=Toj~{c+XkbmpJ=b zW=l+U^Iz0-8a{H_wK^74IKuqKdBD9k_wIV33c^th z(R=sQJmxd#=x5t2R@`00A1-$Sj#JY_Bh-F?Llg~&(Hyt{BB2CWjO_Gu5E+6HuvgRQ z5^iQeBG8-@O z8^9{%%0_%-Aw+{x|;l>7Jgou@r0d0>uY-l-lMtmR=Z7 zik_J*RjT4X7)>zP(0Ze@e;rv$#{7Xi(2C_Lh@^CK$E>&AiV>=65(TXMLc?jL?rVD# zyq?x>xI#uXTknm_cV;4HEhe^c-(>14u>hQD(L`f+YXRBtZoM=HUvrn_vP;WhlevA; z27vv!TtvZZsZ}@5k}ZulUI&S=inntiSJP0-d+e$lmHB|>21mq}dJ+fXQ zi^g@qm&XimdyCk^(T4feO|4gJ-hqdRWr_c~Z&4%;q2UIev69e>#A*jD18@10%Ze(G*kLJgS+6z+~qrp(Ex=$;(U$M@hI;*vIm zlU8D~5^Utd|KuNrrv$to*B$~tSE_J{?YTgTk|n08E;A1<=xR%#vlQ_JS9jm8hGbS29MQ4141`2VE0s~_WPWll`hpt{dLYX~%7mt_ z3-7~oYq7*CP%Q$8?y+wUC+ogrV}c{;fp;)JK)A7SI++6p8z}`6m@o&&>@%_(Xl_{@ z99DuC6^iHW>A721teMqt0GlmSBx^3t&fQ{(==20}ZqucPFmt3Z!SH}9IlaYC0mU}6Q0o`}kk8%-Ob-zw(jxGR=!xwcW zD8?u--6L1PQhMNp^6;87&LeT@xwZE4(M<*`!VT%w#@szq(KksN2qY zu1^1=el-VpohlbJzrpqP^>^5*70ic4(1ug!cpPt#|ADc1E$IWZ#Rxouh=R2avS_JL z^(|4vWWCbVpwF&MQ~C4lmJ??4*BG~jde@Hd9)giAE`$SkD_NxKW3RQq^28l4mT7Wz6Y5*4f zq$xRuUAxf`PpKY)HCPw|J@z(7*lrHJz%`f#+Kn%QEFIpX8-YCJO^=3%IN^}^p6m9% zgp!V3E=vQZ65WguAdUC_Q=pOYmnY9yrOj=-HzC}i>$Be&KrM8`ltgKucHh}QNhZ5m zX%ivr$_@j>v-Yu1Nnnng>PFug&OfmgH?GPlJP;{2T~pa<#U5vPi+CIqb{_|2OR1;g zL`EGKq{UJHR``sWR?m{H=8>pwi}gLoQBbp6?)n9O+d-M`5%3&%DhpY%Y8!d`Q*UBJ zu@fa)WzhB@D6YH}OE1wJcmz@J+rv*^JThBs{M7(xhT)Hgnn?;*T@qI+R|fTK@2?-m z3%f-OPq&@ic+dt+sc)y$3$NEBpb5rzWqp7XB;G9O4}%$`O?*-?$Ly z`erovAif6X0lw0`N(V}FLow`1la!l-ELO(Iqe{MMB?YNrKH$ebRdd;56JxWPbj0Kg zwsUo7=z-zn!(K<^_%) z{gHfb9vq@#2I%qqAa-pY`4GwIKHezzx#K8F47y;6j^T=uoZI{*C`@6Wo3xITXjoL6no=u;LmNXCkEEzxBfb9%-4+8Nv z*skx4Oh5lz|5Rt|37^4A1#;Q~cnCk@Yx_KDn%mT%@>aYdc@7G50fB#4IRoXAWSX0? z3T%`E0oB&q|Lx|*)ON4bs-ittm8KK~d; zT7wtpdFC(_tc#0pS>2Yz^i?^T?B$Jbe~f!%LJ{uDQ}9Ervl9#4Bqza$z4RQMA07nP zclXS{z`rGlZbgfczW-Xv5?GIH71%d}hHYj;9QI5|^1_Mk8d@zi%NLRv2bzK-Dm5Xf zwMnnq23l>lB{nqUB$-F?wT8%q6qv<2h4U_K_#T~1#nb}42<~9qx}KtpbV!N0XJDye zs4w3jLhmgQU?5FyWt?AAj9Cu;Pvj(4ofzs4Ia&LSab{v*^*m$U5X^xEX}LOI2&&e> z>OVJ+nNq*>n*kBHY}z~h7m_(%HSN<#g|$!5yBXPpk(F{57!Vx5EeJ0R5IpU8F7Fl% z)(SwXJ?i^~qkq5H)od1BALPONfTUBoLoS1SDWB;-tBQ#Y&CDjn;z@AytT+8-h|O(% zV1VU#hFGFAdKgzD81ez@xQY0oRe69xWM=u?KUm34e+1e3W$x;Li%_O%Qj@PBPf^Fw z0JC@M{%Tuvr-@HlQ6(4Ct-=J}ypD(idTP3fxU0`t6Po?3i3$2>V{T(odG&Y%bLDDX zg`)H7eCy%E!;c1w)~GRsMCeY6M-1GAoNE4ifuLj;JUgYB$N-%TAYXJI4}(YnP`~f* zb0aUYjS2POl(37_FCJbGa<`K?(}>nI(_gs`48!S!9n6H4aDe_Itq+kS^MOXGKobv9qMyxxmjYriw@bI6(cVvCsLJ66^DG97u`JF_m zfI-jI=qgR~y}z3}OBn7xP9O)Wm{__w#6KImAjW$BiBW&gE>32PO`rbo|ZM)x7sn>0gcx{RY2v&&z+6mXl()o^CZCqFb%dN#g($_ZKbjZ;m zYU%n_$`>XF#UrMcZ0T6iir18;d`pDOfUsTgHo@kP9z*sbAUg)Xv#;bxgPP%I&{2`4 zOoYa`kB-T4!9qkDI1n2*TjB7eka><$V%XcVy=bz$ga8PB(& zlA9IeMU2BounBj`#n2oL|u1URuvOGho8E3Ye0t6CeJ zM}idK;Ga;z1T5|eLAywKn6;ha4_qNMY|SJuS)Vrt%v0Q}0M{E#%8^cCw?S#`>+_DnE_zdfVMQK6Ti3C@nqljmYP1$3g!OBDxx z`xyX+c>>*ahQ%228Mq430Y)>)EqVup;l&o`~zl|3(dC4@wa+r%s`z?yr;Hvg9;7%l;mq}uQo0Dw0H^zR>Zpko!l`Iz1D$z7$AO)35sS1{WPc=MG;Gc zW$N6kx7xWr$1lKIZb2p--zyna8xy|dZfz)<>toe-SO>NysQ59Y9Zw3|3)I?F?p68n zZeX_0?IQI{|5|x>TdrR)jGHk35`HHzR?MboW?W+W(S{=5kU~GrT<+R?q`sS4N3G~HR&phn zX44%LSvP$>&zH##po*Cv@NRRwA(`)9FEBeY=$?u3{ z4tUM;p>N#|w@~?ipccc8<36`F07Hr@oPYd~!r1#AwKN1iGH?DRS9R4|GudR|D(EPQ zlE_cBXV_?tB|);{a;f7Lcd0a0KJXuQaC!y?Qcc%R)V9f8|4|!_YrV4+kjIUWfKpAMZI@lm`=*t%Le$5yCgQAyGc0X<(Df|NZ)$< z7wy1jCHbMu^kr=LR$6vFS9>1^fS4T}E&~~>C-F`;?L9;JNSi7>vJJnQ8TlIw>LH~pD>qLM%P8Ib zS+Kl&NTHkfMzV~&$mD399s7#UI0gVdFspFZUqZZZvaYkU!nOS~*<)4f zHgp|EdU5+2X`Fban2!5%=k6$xo40bh#9r`K0Uu~ZMP#dn&Vdl&c| zn6ZnIHWa*f@tSZlYBlXA{}a*hE@qF{wO+qf^-XOIdFDRsTO@&xlWr+SXs7tj3W2og z9!HrIzTyO4{EY<(L5u_9VDB+Rde`S^tNL6)hBU6^ZEXEcfl)fMovyECe_Uw{gt2Lw zpq;T<1)@S3`v5f%;FNt*>gYov=-M#D%v)=&T1#wL$XO#pU>yv@`)0zb0)2hOdt|pvc{Dma7ct zI?70P>9l&l4kx|HU()rh%&kzSnScto`CDuWnAJX*wruhWDagi7n92KLKa%ZUIr05g zPy0OG99-oVzW7fhrc}j1JtPfvJOrrpRy-s?W9M(UV%?QtK`V9oPqj%XpS}*>{#F9u=ssf>s!w@(NP9)$=}6l^<+Pw zDNaE2Iodo8ohs#JqBjGKPJ$x!QhW385~(lE)2+DUCF^8=76Uv(gV1{gmz32-%(_gr z%ty^sOGRm>KO=aAH|V;}*GgjPM0x|nE}suJ(sRb143vWqsL$?OytEUI%23eE(B|Td zeonb9wm$swIDl&j<~JEdvA>v=b$d}$g0m1L>ZNEHxgBTWL%t; zXLe|nn)q)nAX|72oMS()Pv2HPH}<+#*}Rlv$8kU_GfRy2ymE^uVgD+Pcr2nr(}y3t z>!Spad|;nAbP$mA(R|cO%S8hn|j_qWxidA+Ok(DTI0j zF!%vIe4AaF<0g+tmJPocPAqPF?X4_rA_8bz5CxkDK<&oRafRbMSy>pH;ysXj#^3U=<}Gy{UFOV9NrzaJ+os12rB7h6Kx65?9Fz6i1->$CgqS$S9{> z6w)Lh-ILj7@-~e>QtaR!Oe>fKnl0yOkXPuBx{km7F_#_Z z31(J__Y<&BN}k;DT7O0a$`=}t9?^p9IOfU~59O=S5`9L_!%K(j(3HK4pb&PbX~tp! zq*Rtc#@0G?{K-9rkg(~PDt7$_WGw{q8CChHPk%wNPvUh-b5NVdsZSoLCLfy(UDI6@ z(GcXh&GG%2V**UfXe!^?(W(*eRcAUn*9suioq=pzHmqjnew1L!bF2)0v!&HeC#nt` zg&^M9d|GByJ~Vle&k!#b7<}@?)b$gbI?; zgDMwJD_^Pr^Zz>i{$Z9A(|2g1W6#tkJhBj!tp+%}C67Dr9$_V>*#aUL{dM)YNDSE6gAR39=N3vwX7}bpYrQnYE`hZi%B3qrMM_4 zRqzBM8voDzuxYm9mGMlPKy6$H(n-5hgYL`104uz^8>7bLqiqtuXbt)bgj3RGbfMrH zKP4DDU;y2wPbd}d?p6EOCSQGQ{wfm5EyGP*rizdm*9XE&K;y#L)ILbJXvUY!xK!?5- zyJIk6)}kN9cL0h)z|-_&95#(R&1x#;#IFo_gh-tyNVD3~^qb@)KfCEvLn2bnr(Ei& zHc9GWf8S|&;^(4JPzIKw4FG4*7gwdwMIF-rjuX8ag(BvN)Tc$bXIj}_)2kD}x+!zv z=>I;d{!t)4GmfN`%VAXmQoy`>k`2(3wVwfRdN8v9-b3kdPqbPQIx!5XBNM4wVp=|j zQ^9uZZuVvQ@G#<2=9|=C^0Y_d;?kd6IN`sVC&Robs`iEp-{n4_ze6VWxl$=wl?x+) zMR8ej4uMf-Tbu-u1WG`cnY2~`qG*GvXm@H%Lx-UYyeH?e>d@&medePnZ zZouP(Txqh={&}()IHY6lrtAF;-di>y?{e3{j(CRfw-ryEo}y0s-%Zk44w!Hd&47&U z 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%0AnFzYru^P{8s((;vtn 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 literal 0 HcmV?d00001 diff --git a/Release/samples/CasaLens/CasaLens141/js/default.js b/Release/samples/CasaLens/CasaLens141/js/default.js new file mode 100644 index 0000000000..b7e1ea2339 --- /dev/null +++ b/Release/samples/CasaLens/CasaLens141/js/default.js @@ -0,0 +1,173 @@ +function formatAMPM(date) { + var hours = date.getHours(); + var minutes = date.getMinutes(); + var ampm = hours >= 12 ? 'pm' : 'am'; + hours = hours % 12; + hours = hours ? hours : 12; // the hour '0' should be '12' + minutes = minutes < 10 ? '0' + minutes : minutes; + var strTime = hours + ':' + minutes + ' ' + ampm; + return strTime; +} + +function formatEventTime(dateTimeStr) { + dateTimeStr = dateTimeStr.substr(0, dateTimeStr.lastIndexOf(":")).split(" ").join("T") + var dateObj = new Date(dateTimeStr); + if (!dateObj) { + return ""; + } + var dateStr = dateObj.toDateString(); + dateStr = dateStr.substring(0, dateStr.length - 5); + return dateStr + "
" + formatAMPM(dateObj); +} + +function ClearText() { + location_ip.value = ""; +} + +function TrimText(text, maxLength) { + if (text.length < maxLength) { + return text; + } else { + var i = maxLength; + while (i < text.length) { + + if (text[i] == " " || text[i] == "," || text[i] == "." || text[i] == "\r" || text[i] == "\n") { + break; + } + i++; + } + return text.substr(0, i); + } +} + +function populateEvents(events) { + + var tempDiv = document.createElement("div"); + + var currentChildNodes = eventsTable.childNodes; + var defaultChildrenCount = 2; + for (var i = defaultChildrenCount; i < currentChildNodes.length; i++) { + currentChildNodes[i].parentNode.removeChild(currentChildNodes[i]); + } + for (var i = 0; i < events.length; i++) { + var dataObj = events[i]; + + tempDiv.innerHTML = dataObj.description; + var description = TrimText(tempDiv.innerText, 150); + var innerHtml = eventTemplate.innerHTML; + innerHtml = innerHtml.replace("%eventtitle%", TrimText(dataObj.title, 30)); + innerHtml = innerHtml.replace("%eventstarttime%", formatEventTime(dataObj.starttime)); + innerHtml = innerHtml.replace("%eventdescription%", description); + innerHtml = innerHtml.replace("%eventlink1%", dataObj.url); + innerHtml = innerHtml.replace("%eventlink2%", dataObj.url); + innerHtml = innerHtml.replace("%eventvenue%", dataObj.venue_address); + var obj = document.createElement("tr"); + obj.innerHTML = window.toStaticHTML(innerHtml); + + eventsTable.appendChild(obj); + } +} + +function populateWeather(weather) { + + var currentChildNodes = weatherData.childNodes; + var defaultChildrenCount = 5; + for (var i = defaultChildrenCount; i < currentChildNodes.length; i++) { + currentChildNodes[i].parentNode.removeChild(currentChildNodes[i]); + } + + var weatherElement = weatherTemplate.cloneNode(true); + weatherElement.style.display = "inherit"; + var innerHtml = weatherElement.innerHTML; + innerHtml = innerHtml.replace("%wt%", weather.temperature); + innerHtml = innerHtml.replace("%wp%", weather.pressure); + innerHtml = innerHtml.replace("%wtmin%", weather.temp_min); + innerHtml = innerHtml.replace("%wtmax%", weather.temp_max); + innerHtml = innerHtml.replace("%wdesc%", weather.description); + innerHtml = innerHtml.replace("%wimg%", weather.image); + weatherElement.innerHTML = window.toStaticHTML(innerHtml); + weatherData.appendChild(weatherElement); +} + +function populateMovies(movies) { + + var currentChildNodes = movieTemplateToHide.childNodes; + var defaultChildrenCount = 3; + for (var i = defaultChildrenCount; i < currentChildNodes.length; i++) { + currentChildNodes[i].parentNode.removeChild(currentChildNodes[i]); + } + + var showtimes = ""; + for (var i = 0; i < movies.length; i++) { + var innerHtml = movieTemplate.innerHTML; + var dataObj = movies[i]; + + var theatrename; + for (var j = 0; j < dataObj.theatre.length; j++) { + + showtimes += dataObj.theatre[j].name; + showtimes += "
"; + var showtimelist = dataObj.theatre[j].datetime; + for (var k = 0; k < showtimelist.length; k++) { + var dateObj = new Date(showtimelist[k]); + if (dateObj) { + showtimes += formatAMPM(dateObj) + " | "; + } + } + showtimes = showtimes.substr(0, showtimes.length - 2); + showtimes += "

"; + } + innerHtml = innerHtml.replace("%mtitle%", dataObj.title); + innerHtml = innerHtml.replace("%mtheater%", showtimes); + innerHtml = innerHtml.replace("%mposter%", dataObj.poster); + + var obj = document.createElement("div"); + obj.innerHTML = window.toStaticHTML(innerHtml); + movieTemplateToHide.appendChild(obj); + } +} + +function populateImages(images) { + if (images.length == 4) { + var mainimg = document.getElementById('mainPic1'); + mainimg.src = images[0]; + + var img1 = document.getElementById('thumbnailPic1'); + img1.src = images[1]; + + var img2 = document.getElementById('thumbnailPic2'); + img2.src = images[2]; + + var img3 = document.getElementById('thumbnailPic3'); + img3.src = images[3]; + } +} + +function FetchData() { + var xhr = new XMLHttpRequest(); + xhr.onreadystatechange = function (e) { + // The request finished and response is ready + if (xhr.readyState == 4) { + var searchbar = document.getElementById('searchBar'); + searchbar.style.display = 'none'; + + if (xhr.status == 200) { + var replydata = JSON.parse(xhr.responseText); + populateImages(replydata.images); + populateEvents(replydata.events); + populateMovies(replydata.movies); + populateWeather(replydata.weather); + + defaultData.style.display = "none"; + cityData.style.display = 'inherit'; + } + else { + defaultData.style.display = "none"; + errorData.style.display = 'inherit'; + } + } + } + xhr.open("POST", document.URL, true); + xhr.setRequestHeader("Content-type", 'text/html'); + xhr.send(location_ip.value); +} diff --git a/Release/samples/CasaLens/casalens.cpp b/Release/samples/CasaLens/casalens.cpp index 6b436c5cab..4caac60d46 100644 --- a/Release/samples/CasaLens/casalens.cpp +++ b/Release/samples/CasaLens/casalens.cpp @@ -94,7 +94,7 @@ void CasaLens::handle_get(http_request message) concurrency::streams::fstream::open_istream(file_name, std::ios::in).then([=](concurrency::streams::istream is) { message.reply(status_codes::OK, is, content_type).then([](pplx::task t) { handle_error(t); }); - }).then([=](pplx::task& t) + }).then([=](pplx::task t) { try { diff --git a/Release/samples/CasaLens/datafetcher.cpp b/Release/samples/CasaLens/datafetcher.cpp index b3e41ada00..7f5c55d1c5 100644 --- a/Release/samples/CasaLens/datafetcher.cpp +++ b/Release/samples/CasaLens/datafetcher.cpp @@ -408,7 +408,7 @@ void CasaLens::get_data(http_request message, const std::wstring& input_text) bing_client.request(methods::GET, s).then([=](http_response resp) { return resp.extract_json(); - }).then([=](json::value& maps_result) mutable + }).then([=](json::value maps_result) mutable { auto coordinates = maps_result[U("resourceSets")][0][U("resources")][0][U("point")]; auto lattitude = coordinates[U("coordinates")][0].serialize(); @@ -420,10 +420,10 @@ void CasaLens::get_data(http_request message, const std::wstring& input_text) }).then([](http_response resp) { return resp.extract_json(); - }).then([=](json::value& maps_result) + }).then([=](json::value maps_result) { auto postal_code = maps_result[U("resourceSets")][0][U("resources")][0][U("address")][U("postalCode")].as_string(); - fetch_data(message, postal_code, input_text); + fetch_data(message, postal_code, input_text); }).then([=](pplx::task t) { try diff --git a/Release/samples/FacebookDemo/FacebookDemo120.vcxproj b/Release/samples/FacebookDemo/FacebookDemo120.vcxproj index 8a5e649a0e..c09ba7fb72 100644 --- a/Release/samples/FacebookDemo/FacebookDemo120.vcxproj +++ b/Release/samples/FacebookDemo/FacebookDemo120.vcxproj @@ -144,7 +144,7 @@ - + Designer diff --git a/Release/samples/FacebookDemo/FacebookDemo140.vcxproj b/Release/samples/FacebookDemo/FacebookDemo140.vcxproj index 25ee7d2c3d..bd249ff292 100644 --- a/Release/samples/FacebookDemo/FacebookDemo140.vcxproj +++ b/Release/samples/FacebookDemo/FacebookDemo140.vcxproj @@ -143,7 +143,7 @@ - + Designer diff --git a/Release/samples/FacebookDemo/FacebookDemo141.vcxproj b/Release/samples/FacebookDemo/FacebookDemo141.vcxproj new file mode 100644 index 0000000000..af5715d233 --- /dev/null +++ b/Release/samples/FacebookDemo/FacebookDemo141.vcxproj @@ -0,0 +1,184 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658} + FacebookDemo + en-US + 14.0 + true + Windows Store + 10.0.10240.0 + 10.0.10240.0 + 10.0 + + + + Application + true + v141 + + + Application + true + v141 + + + Application + true + v141 + + + Application + false + true + v141 + + + Application + false + true + v141 + + + Application + false + true + v141 + + + + + + + FacebookDemo_TemporaryKey.pfx + + + $(OutDir)\$(MSBuildProjectName)\ + + + + /bigobj %(AdditionalOptions) + 4453 + $(MSBuildProjectDirectory);$(CasablancaIncludeDir);$(MSBuildProjectDirectory)\Generated Files;%(AdditionalIncludeDirectories) + + + + + /bigobj %(AdditionalOptions) + 4453 + $(MSBuildProjectDirectory);$(CasablancaIncludeDir);$(MSBuildProjectDirectory)\Generated Files;%(AdditionalIncludeDirectories) + + + + + /bigobj /Zm137 %(AdditionalOptions) + 4453 + $(MSBuildProjectDirectory);$(CasablancaIncludeDir);$(MSBuildProjectDirectory)\Generated Files;%(AdditionalIncludeDirectories) + + + + + /bigobj %(AdditionalOptions) + 4453 + $(MSBuildProjectDirectory);$(CasablancaIncludeDir);$(MSBuildProjectDirectory)\Generated Files;%(AdditionalIncludeDirectories) + + + + + /bigobj %(AdditionalOptions) + 4453 + $(MSBuildProjectDirectory);$(CasablancaIncludeDir);$(MSBuildProjectDirectory)\Generated Files;%(AdditionalIncludeDirectories) + + + + + /bigobj %(AdditionalOptions) + 4453 + $(MSBuildProjectDirectory);$(CasablancaIncludeDir);$(MSBuildProjectDirectory)\Generated Files;%(AdditionalIncludeDirectories) + + + + + + + App.xaml + + + MainPage.xaml + + + + + Designer + + + Designer + + + Designer + + + + + Designer + + + + + + + + + + + + App.xaml + + + + MainPage.xaml + + + Create + Create + Create + Create + Create + Create + + + + + {198ed804-2655-4d92-8104-c220e3ea9452} + + + + + + \ No newline at end of file diff --git a/Release/samples/FacebookDemo/Package120.appxmanifest b/Release/samples/FacebookDemo/Package.appxmanifest similarity index 93% rename from Release/samples/FacebookDemo/Package120.appxmanifest rename to Release/samples/FacebookDemo/Package.appxmanifest index 51de7429ba..10e0fb86ab 100644 --- a/Release/samples/FacebookDemo/Package120.appxmanifest +++ b/Release/samples/FacebookDemo/Package.appxmanifest @@ -7,8 +7,8 @@ Assets\StoreLogo.png - 6.2.1 - 6.2.1 + 10.0 + 10.0 diff --git a/Release/samples/FacebookDemo/Package.uwp.appxmanifest b/Release/samples/FacebookDemo/Package.uwp.appxmanifest new file mode 100644 index 0000000000..2c22a5313a --- /dev/null +++ b/Release/samples/FacebookDemo/Package.uwp.appxmanifest @@ -0,0 +1,34 @@ + + + + + FacebookDemo + Andy + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Release/samples/FacebookDemo/Package110.appxmanifest b/Release/samples/FacebookDemo/Package110.appxmanifest deleted file mode 100644 index 92b3781c45..0000000000 --- a/Release/samples/FacebookDemo/Package110.appxmanifest +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - FacebookDemo - Andy - Assets\StoreLogo.png - - - - 6.2.1 - 6.2.1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/samples/FacebookDemo/Package140.appxmanifest b/Release/samples/FacebookDemo/Package140.appxmanifest deleted file mode 100644 index 92b3781c45..0000000000 --- a/Release/samples/FacebookDemo/Package140.appxmanifest +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - FacebookDemo - Andy - Assets\StoreLogo.png - - - - 6.2.1 - 6.2.1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/samples/OAuth2Live/OAuth2Live120.vcxproj b/Release/samples/OAuth2Live/OAuth2Live120.vcxproj index ba5f229042..505d507611 100644 --- a/Release/samples/OAuth2Live/OAuth2Live120.vcxproj +++ b/Release/samples/OAuth2Live/OAuth2Live120.vcxproj @@ -150,7 +150,7 @@ - + Designer diff --git a/Release/samples/OAuth2Live/OAuth2Live140.vcxproj b/Release/samples/OAuth2Live/OAuth2Live140.vcxproj index 536709ab38..6671f9c227 100644 --- a/Release/samples/OAuth2Live/OAuth2Live140.vcxproj +++ b/Release/samples/OAuth2Live/OAuth2Live140.vcxproj @@ -150,7 +150,7 @@ - + Designer diff --git a/Release/samples/OAuth2Live/OAuth2Live141.vcxproj b/Release/samples/OAuth2Live/OAuth2Live141.vcxproj new file mode 100644 index 0000000000..4607d183a0 --- /dev/null +++ b/Release/samples/OAuth2Live/OAuth2Live141.vcxproj @@ -0,0 +1,190 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {2887A786-B818-4B3D-94EF-21EFD6AFDC22} + OAuth2Live + en-US + 14.0 + true + Windows Store + 10.0.10240.0 + 10.0.10240.0 + 10.0 + + + + Application + true + v141 + + + Application + true + v141 + + + Application + true + v141 + + + Application + false + true + v141 + + + Application + false + true + v141 + + + Application + false + true + v141 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /bigobj /Zm200 %(AdditionalOptions) + 4453 + $(MSBuildProjectDirectory);$(CasablancaIncludeDir);$(MSBuildProjectDirectory)\Generated Files;%(AdditionalIncludeDirectories) + + + + $(OutDir)\$(MSBuildProjectName)\ + + + OAuth2Live_TemporaryKey.pfx + + + + + App.xaml + + + MainPage.xaml + + + + + Designer + + + Designer + + + Designer + + + + + Designer + + + + + + + + + + + + App.xaml + + + MainPage.xaml + + + Create + Create + Create + Create + Create + Create + + + + + {198ed804-2655-4d92-8104-c220e3ea9452} + + + + + + \ No newline at end of file diff --git a/Release/samples/OAuth2Live/Package120.appxmanifest b/Release/samples/OAuth2Live/Package.appxmanifest similarity index 100% rename from Release/samples/OAuth2Live/Package120.appxmanifest rename to Release/samples/OAuth2Live/Package.appxmanifest diff --git a/Release/samples/OAuth2Live/Package.uwp.appxmanifest b/Release/samples/OAuth2Live/Package.uwp.appxmanifest new file mode 100644 index 0000000000..1c43d54562 --- /dev/null +++ b/Release/samples/OAuth2Live/Package.uwp.appxmanifest @@ -0,0 +1,34 @@ + + + + + OAuth2Live + Andy + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Release/samples/OAuth2Live/Package110.appxmanifest b/Release/samples/OAuth2Live/Package110.appxmanifest deleted file mode 100644 index d43e5de92a..0000000000 --- a/Release/samples/OAuth2Live/Package110.appxmanifest +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - OAuth2Live - symbiouser - Assets\StoreLogo.png - - - - 6.2.1 - 6.2.1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/samples/OAuth2Live/Package140.appxmanifest b/Release/samples/OAuth2Live/Package140.appxmanifest deleted file mode 100644 index fc1171601e..0000000000 --- a/Release/samples/OAuth2Live/Package140.appxmanifest +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - OAuth2Live - Microsoft Corporation - Assets\StoreLogo.png - - - - 6.2.1 - 6.2.1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj b/Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj new file mode 100644 index 0000000000..9dff0e2207 --- /dev/null +++ b/Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj @@ -0,0 +1,204 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {850CCB95-CFA8-4E41-9D1D-387C0C186740} + Win32Proj + Oauth1Client + SAK + SAK + SAK + SAK + $(VCTargetsPath12) + + + + Application + true + NotSet + v141 + + + Application + true + NotSet + v141 + + + Application + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + true + true + + + + + + + + + + Create + Create + Create + Create + Create + Create + + + + + + + + \ No newline at end of file diff --git a/Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj.filters b/Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj.filters new file mode 100644 index 0000000000..48d2ebae5f --- /dev/null +++ b/Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj b/Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj new file mode 100644 index 0000000000..a0d3d0fdeb --- /dev/null +++ b/Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj @@ -0,0 +1,205 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654} + Win32Proj + Oauth2Client + SAK + SAK + SAK + SAK + $(VCTargetsPath12) + + + + Application + true + NotSet + v141 + + + Application + true + NotSet + v141 + + + Application + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + -Zm140 %(AdditionalOptions) + + + Console + true + true + true + + + + + + + + + + Create + Create + Create + Create + Create + Create + + + + + {1014c621-bc2d-4813-b8c1-6d83ad6f9249} + + + + \ No newline at end of file diff --git a/Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj.filters b/Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj.filters new file mode 100644 index 0000000000..d11e5aec8b --- /dev/null +++ b/Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj b/Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj new file mode 100644 index 0000000000..7fa2bd5235 --- /dev/null +++ b/Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj @@ -0,0 +1,146 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F03BEE03-BEFB-4B17-A774-D9C8246530D4} + SAK + SAK + SAK + SAK + Win32Proj + $(VCTargetsPath12) + + + + Application + true + NotSet + v141 + + + Application + true + NotSet + v141 + + + Application + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + Application + false + true + NotSet + v141 + + + + + + + /bigobj %(AdditionalOptions) + NotUsing + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + + + Console + true + + + + + /bigobj %(AdditionalOptions) + NotUsing + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + + + Console + true + + + + + /bigobj %(AdditionalOptions) + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + + + Console + true + true + true + + + + + /bigobj %(AdditionalOptions) + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(CasablancaIncludeDir) + Async + + + Console + true + true + true + + + + + {1014c621-bc2d-4813-b8c1-6d83ad6f9249} + + + + + + + \ No newline at end of file diff --git a/Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj.filters b/Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj.filters new file mode 100644 index 0000000000..2794140178 --- /dev/null +++ b/Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj.filters @@ -0,0 +1,13 @@ + + + + + {bc214923-f806-44a3-abd4-08a1aa1a9b3b} + + + + + Source Files + + + \ No newline at end of file diff --git a/Release/samples/WindowsLiveAuth/Package120.appxmanifest b/Release/samples/WindowsLiveAuth/Package.appxmanifest similarity index 100% rename from Release/samples/WindowsLiveAuth/Package120.appxmanifest rename to Release/samples/WindowsLiveAuth/Package.appxmanifest diff --git a/Release/samples/WindowsLiveAuth/Package140.appxmanifest b/Release/samples/WindowsLiveAuth/Package140.appxmanifest deleted file mode 100644 index c3bed31403..0000000000 --- a/Release/samples/WindowsLiveAuth/Package140.appxmanifest +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - WindowsLiveAuth - Microsoft Corporation - Assets\StoreLogo.png - - - - 6.2.1 - 6.2.1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/samples/WindowsLiveAuth/WindowsLiveAuth120.vcxproj b/Release/samples/WindowsLiveAuth/WindowsLiveAuth120.vcxproj index 4befa38ebd..2efbe5d141 100644 --- a/Release/samples/WindowsLiveAuth/WindowsLiveAuth120.vcxproj +++ b/Release/samples/WindowsLiveAuth/WindowsLiveAuth120.vcxproj @@ -152,7 +152,7 @@ - + Designer diff --git a/Release/samples/WindowsLiveAuth/WindowsLiveAuth140.vcxproj b/Release/samples/WindowsLiveAuth/WindowsLiveAuth140.vcxproj index 7a04658c9a..7be6b6dda1 100644 --- a/Release/samples/WindowsLiveAuth/WindowsLiveAuth140.vcxproj +++ b/Release/samples/WindowsLiveAuth/WindowsLiveAuth140.vcxproj @@ -151,7 +151,7 @@ - + Designer diff --git a/Release/samples/WindowsLiveAuth/WindowsLiveAuth141.vcxproj b/Release/samples/WindowsLiveAuth/WindowsLiveAuth141.vcxproj new file mode 100644 index 0000000000..3983220d9e --- /dev/null +++ b/Release/samples/WindowsLiveAuth/WindowsLiveAuth141.vcxproj @@ -0,0 +1,191 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {1c20f771-3131-46e8-805f-aa1fe44165c0} + WindowsLiveAuth + en-US + 14.0 + true + Windows Store + 10.0.10240.0 + 10.0.10240.0 + 10.0 + + + + Application + true + v140 + + + Application + true + v140 + + + Application + true + v140 + + + Application + false + true + v140 + + + Application + false + true + v140 + + + Application + false + true + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /bigobj /Zm200 %(AdditionalOptions) + 4453 + $(MSBuildProjectDirectory);$(CasablancaIncludeDir);$(MSBuildProjectDirectory)\Generated Files;%(AdditionalIncludeDirectories) + + + + $(OutDir)\$(MSBuildProjectName)\ + + + WindowsLiveAuth_TemporaryKey.pfx + + + + + + App.xaml + + + MainPage.xaml + + + + + Designer + + + Designer + + + Designer + + + + + Designer + + + + + + + + + + + + App.xaml + + + MainPage.xaml + + + Create + Create + Create + Create + Create + Create + + + + + {198ed804-2655-4d92-8104-c220e3ea9452} + + + + + + \ No newline at end of file diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 9391da3cc8..1c460684ab 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -249,7 +249,7 @@ endif() # Portions specific to cpprest binary versioning. set (CPPREST_VERSION_MAJOR 2) -set (CPPREST_VERSION_MINOR 9) +set (CPPREST_VERSION_MINOR 10) set (CPPREST_VERSION_REVISION 0) if(WIN32) diff --git a/Release/src/build/common.vcxitems b/Release/src/build/common.vcxitems index 96e64635fb..8e9142fa9a 100644 --- a/Release/src/build/common.vcxitems +++ b/Release/src/build/common.vcxitems @@ -1,100 +1,95 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 248F659F-DAC5-46E8-AC09-60EC9FC95053 - true - b19fa703-0bf0-4e1f-8927-b0eaeb6aa823 - {594dcb5f-07e3-4084-a2ce-268611fa629f} - common - common - - - - %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) - - - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Designer - - + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + 248F659F-DAC5-46E8-AC09-60EC9FC95053 + true + b19fa703-0bf0-4e1f-8927-b0eaeb6aa823 + {594dcb5f-07e3-4084-a2ce-268611fa629f} + common + common + + + + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + + + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Release/src/build/common.vcxitems.filters b/Release/src/build/common.vcxitems.filters index 055bff167f..437868082e 100644 --- a/Release/src/build/common.vcxitems.filters +++ b/Release/src/build/common.vcxitems.filters @@ -1,236 +1,233 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - {3bdf9ddb-6199-4b83-84cd-e8617e78294e} - - - {42f86193-fcdc-443d-8ede-8fd31abe6643} - - - {ed89d519-15d6-47d9-90cb-e6c25bcaa323} - - - {e5ecd256-178a-403a-9249-5d15463ad051} - - - {d32b3879-7333-4ab4-8ef2-dd72aed7b5dc} - - - {1c12997c-5bf5-4b60-853e-a5f9c8303760} - - - {97da7aee-41c8-4948-bb0e-c31cec1bfb16} - - - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\pch - - - Header Files\pplx - - - Header Files\pplx - - - Header Files\pplx - - - Header Files\pplx - - - Header Files\pplx - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest - - - Header Files\cpprest\details - - - Header Files\private - - - Header Files\private - - - Header Files\private - - - Header Files\private - - - - - Header Files\cpprest\details - - - - - + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + {3bdf9ddb-6199-4b83-84cd-e8617e78294e} + + + {42f86193-fcdc-443d-8ede-8fd31abe6643} + + + {ed89d519-15d6-47d9-90cb-e6c25bcaa323} + + + {e5ecd256-178a-403a-9249-5d15463ad051} + + + {d32b3879-7333-4ab4-8ef2-dd72aed7b5dc} + + + {1c12997c-5bf5-4b60-853e-a5f9c8303760} + + + {97da7aee-41c8-4948-bb0e-c31cec1bfb16} + + + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\pch + + + Header Files\pplx + + + Header Files\pplx + + + Header Files\pplx + + + Header Files\pplx + + + Header Files\pplx + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\cpprest + + + Header Files\cpprest\details + + + Header Files\private + + + Header Files\private + + + Header Files\private + + + Header Files\private + + + + + Header Files\cpprest\details + + \ No newline at end of file diff --git a/Release/src/build/init.ps1 b/Release/src/build/init.ps1 index 68a35fbc13..595baeaaa9 100644 --- a/Release/src/build/init.ps1 +++ b/Release/src/build/init.ps1 @@ -5,7 +5,7 @@ function Copy-Natvis($DestFolder) if ((Test-Path $DestFolder) -eq $True) { # Update casablanca version for each release here. - $DestFile = Join-Path -path $DestFolder -childpath "cpprest2_8.natvis"; + $DestFile = Join-Path -path $DestFolder -childpath "cpprest2_10.natvis"; # Check to see if cpp rest natvis file for this version already exists # if not, then copy into user profile for Visual Studio to pick up diff --git a/Release/src/build/package_info.xml b/Release/src/build/package_info.xml deleted file mode 100644 index a2f9550b13..0000000000 --- a/Release/src/build/package_info.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - cpprestsdk - 2.9.0 - casablancacore - Microsoft, Visual C++ - http://www.apache.org/licenses/LICENSE-2.0 - https://github.com/Microsoft/cpprestsdk/ - https://download-codeplex.sec.s-msft.com/Download?ProjectName=casablanca&DownloadId=630102&Build=20425 - false -

The C++ REST SDK is a cross-platform, modern, and asynchronous library that enables developers to access and author connected applications. - The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design. This project aims to help C++ developers connect to and interact with services. - https://github.com/Microsoft/cpprestsdk/releases/tag/v2.9.0 - Copyright 2015 - cpprestsdk Casablanca REST JSON HTTP URI WebSockets - - ..\..\include - - - - - - - - - - - /d2notypeopt %(AdditionalOptions) - CPPREST_TARGET_XP;%(PreprocessorDefinitions) - - -funwind-tables %(AdditionalOptions) - - - m;%(LibraryDependencies) - - - - \ No newline at end of file diff --git a/Release/src/build/vs141.uwp/cpprest141.uwp.vcxproj b/Release/src/build/vs141.uwp/cpprest141.uwp.vcxproj new file mode 100644 index 0000000000..874315ee1f --- /dev/null +++ b/Release/src/build/vs141.uwp/cpprest141.uwp.vcxproj @@ -0,0 +1,91 @@ + + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} + DynamicLibrary + en-US + 14.0 + true + Windows Store + 10.0.10240.0 + 10.0.10240.0 + 10.0 + cpprest141.uwp + v141 + DynamicLibrary + $(OutDir)\$(MsBuildProjectName) + + + + + + + + + + + + + + + + d + + + $(CppRestBaseFileName)141$(DebugFileSuffix)_uwp_$(CppRestSDKVersionFileSuffix) + + + + + false + false + + + + _ASYNCRT_EXPORT;_PPLX_EXPORT;_USRDLL;%(PreprocessorDefinitions); + Use + true + $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;%(AdditionalIncludeDirectories) + Use + stdafx.h + -Zm250 /bigobj %(AdditionalOptions) + true + + + Console + false + UseLinkTimeCodeGeneration + false + + + + + + \ No newline at end of file diff --git a/Release/src/build/vs141/cpprest141.vcxproj b/Release/src/build/vs141/cpprest141.vcxproj new file mode 100644 index 0000000000..323553b4cc --- /dev/null +++ b/Release/src/build/vs141/cpprest141.vcxproj @@ -0,0 +1,78 @@ + + + + + {1014C621-BC2D-4813-B8C1-6D83AD6F9249} + Win32Proj + SAK + SAK + SAK + SAK + DynamicLibrary + v141 + false + false + cpprest141 + + + + + + + + + + + + + + + + + + + d + + + $(CppRestBaseFileName)141$(DebugFileSuffix)_$(CppRestSDKVersionFileSuffix) + + + + Designer + + + + + _ASYNCRT_EXPORT;_PPLX_EXPORT;WIN32;_MBCS;_USRDLL;%(PreprocessorDefinitions) + $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) + Use + stdafx.h + -Zm300 /bigobj %(AdditionalOptions) + MultiThreadedDebugDLL + MultiThreadedDLL + true + + + 4503;4592;%(DisableSpecificWarnings) + 4503;4592;%(DisableSpecificWarnings) + 4503;4592;%(DisableSpecificWarnings) + 4503;4592;%(DisableSpecificWarnings) + 4503;4592;%(DisableSpecificWarnings) + 4503;4592;%(DisableSpecificWarnings) + + + Winhttp.lib;httpapi.lib;bcrypt.lib;crypt32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/Release/src/build/vs141/packages.config b/Release/src/build/vs141/packages.config new file mode 100644 index 0000000000..21a51fdf83 --- /dev/null +++ b/Release/src/build/vs141/packages.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/cpprestsdk141.sln b/cpprestsdk141.sln new file mode 100644 index 0000000000..1d0d59b04c --- /dev/null +++ b/cpprestsdk141.sln @@ -0,0 +1,243 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27016.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "android", "Release\src\build\android.vcxitems", "{65951C40-A332-4B54-89C2-7CDAF30D5F66}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "Release\src\build\common.vcxitems", "{594DCB5F-07E3-4084-A2CE-268611FA629F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "other", "Release\src\build\other.vcxitems", "{3D5908F7-7673-4229-BC46-2007A7AF9CAE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win32", "Release\src\build\win32.vcxitems", "{F40F4804-50F9-4257-8D74-B9CBB19AC4C3}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winrt", "Release\src\build\winrt.vcxitems", "{0A9BA181-7876-4B3D-A5E0-EE673FA51C05}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{92944FCF-7E50-41FD-8A99-DD6869F9AEA5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprest141", "Release\src\build\vs141\cpprest141.vcxproj", "{1014C621-BC2D-4813-B8C1-6D83AD6F9249}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprest141.uwp", "Release\src\build\vs141.uwp\cpprest141.uwp.vcxproj", "{36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{EF775754-D70A-4611-A00C-F49F224FD236}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SearchFile141", "Release\samples\SearchFile\SearchFile141\SearchFile141.vcxproj", "{F03BEE03-BEFB-4B17-A774-D9C8246530D4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OAuth2Live141", "Release\samples\OAuth2Live\OAuth2Live141.vcxproj", "{2887A786-B818-4B3D-94EF-21EFD6AFDC22}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Oauth2Client141", "Release\samples\Oauth2Client\Oauth2Client141\Oauth2Client141.vcxproj", "{35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Oauth1Client141", "Release\samples\Oauth1Client\Oauth1Client141\Oauth1Client141.vcxproj", "{850CCB95-CFA8-4E41-9D1D-387C0C186740}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FacebookDemo141", "Release\samples\FacebookDemo\FacebookDemo141.vcxproj", "{43DE4DF3-ACAA-429E-B260-CC6D4FE82658}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CasaLens141", "Release\samples\CasaLens\CasaLens141\CasaLens141.vcxproj", "{FFBFD6C1-B525-4D35-AB64-A2FE9460B147}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlackJack_UIClient141", "Release\samples\BlackJack\BlackJack_UIClient\BlackJack_UIClient141.vcxproj", "{B8D3F85B-DA71-4ACA-87BA-10FED681DC79}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlackJack_Server141", "Release\samples\BlackJack\BlackJack_Server\BlackJack_Server141\BlackJack_Server141.vcxproj", "{84350CD1-D406-4A4F-9571-261CA46D77C5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlackJack_Client141", "Release\samples\BlackJack\BlackJack_Client\BlackJack_Client141\BlackJack_Client141.vcxproj", "{830B6E2F-9224-41D1-B9C7-A51FC78B00C7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BingRequest141", "Release\samples\BingRequest\BingRequest141\BingRequest141.vcxproj", "{2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}" +EndProject +Global + GlobalSection(SharedMSBuildProjectFiles) = preSolution + Release\src\build\winrt.vcxitems*{0a9ba181-7876-4b3d-a5e0-ee673fa51c05}*SharedItemsImports = 9 + Release\src\build\common.vcxitems*{1014c621-bc2d-4813-b8c1-6d83ad6f9249}*SharedItemsImports = 4 + Release\src\build\win32.vcxitems*{1014c621-bc2d-4813-b8c1-6d83ad6f9249}*SharedItemsImports = 4 + Release\src\build\common.vcxitems*{36d79e79-7e9e-4b3a-88a3-9f9b295c80b9}*SharedItemsImports = 4 + Release\src\build\winrt.vcxitems*{36d79e79-7e9e-4b3a-88a3-9f9b295c80b9}*SharedItemsImports = 4 + Release\src\build\other.vcxitems*{3d5908f7-7673-4229-bc46-2007a7af9cae}*SharedItemsImports = 9 + Release\src\build\common.vcxitems*{594dcb5f-07e3-4084-a2ce-268611fa629f}*SharedItemsImports = 9 + Release\src\build\android.vcxitems*{65951c40-a332-4b54-89c2-7cdaf30d5f66}*SharedItemsImports = 9 + Release\src\build\win32.vcxitems*{f40f4804-50f9-4257-8d74-b9cbb19ac4c3}*SharedItemsImports = 9 + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|ARM = Release|ARM + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|ARM.ActiveCfg = Debug|ARM + {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|ARM.Build.0 = Debug|ARM + {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|x64.ActiveCfg = Debug|x64 + {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|x64.Build.0 = Debug|x64 + {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|x86.ActiveCfg = Debug|Win32 + {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|x86.Build.0 = Debug|Win32 + {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|ARM.ActiveCfg = Release|ARM + {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|ARM.Build.0 = Release|ARM + {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|x64.ActiveCfg = Release|x64 + {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|x64.Build.0 = Release|x64 + {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|x86.ActiveCfg = Release|Win32 + {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|x86.Build.0 = Release|Win32 + {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|ARM.ActiveCfg = Debug|ARM + {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|ARM.Build.0 = Debug|ARM + {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|x64.ActiveCfg = Debug|x64 + {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|x64.Build.0 = Debug|x64 + {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|x86.ActiveCfg = Debug|Win32 + {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|x86.Build.0 = Debug|Win32 + {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|ARM.ActiveCfg = Release|ARM + {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|ARM.Build.0 = Release|ARM + {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|x64.ActiveCfg = Release|x64 + {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|x64.Build.0 = Release|x64 + {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|x86.ActiveCfg = Release|Win32 + {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|x86.Build.0 = Release|Win32 + {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|ARM.ActiveCfg = Debug|Win32 + {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|x64.ActiveCfg = Debug|x64 + {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|x64.Build.0 = Debug|x64 + {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|x86.ActiveCfg = Debug|Win32 + {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|x86.Build.0 = Debug|Win32 + {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|ARM.ActiveCfg = Release|Win32 + {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|x64.ActiveCfg = Release|x64 + {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|x64.Build.0 = Release|x64 + {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|x86.ActiveCfg = Release|Win32 + {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|x86.Build.0 = Release|Win32 + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|ARM.ActiveCfg = Debug|ARM + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|ARM.Build.0 = Debug|ARM + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|ARM.Deploy.0 = Debug|ARM + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|x64.ActiveCfg = Debug|x64 + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|x64.Build.0 = Debug|x64 + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|x64.Deploy.0 = Debug|x64 + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|x86.ActiveCfg = Debug|Win32 + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|x86.Build.0 = Debug|Win32 + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|x86.Deploy.0 = Debug|Win32 + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|ARM.ActiveCfg = Release|ARM + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|ARM.Build.0 = Release|ARM + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|ARM.Deploy.0 = Release|ARM + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|x64.ActiveCfg = Release|x64 + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|x64.Build.0 = Release|x64 + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|x64.Deploy.0 = Release|x64 + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|x86.ActiveCfg = Release|Win32 + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|x86.Build.0 = Release|Win32 + {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|x86.Deploy.0 = Release|Win32 + {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Debug|ARM.ActiveCfg = Debug|ARM + {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Debug|ARM.Build.0 = Debug|ARM + {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Debug|x64.ActiveCfg = Debug|x64 + {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Debug|x64.Build.0 = Debug|x64 + {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Debug|x86.ActiveCfg = Debug|Win32 + {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Debug|x86.Build.0 = Debug|Win32 + {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Release|ARM.ActiveCfg = Release|ARM + {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Release|ARM.Build.0 = Release|ARM + {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Release|x64.ActiveCfg = Release|x64 + {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Release|x64.Build.0 = Release|x64 + {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Release|x86.ActiveCfg = Release|Win32 + {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Release|x86.Build.0 = Release|Win32 + {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Debug|ARM.ActiveCfg = Debug|ARM + {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Debug|ARM.Build.0 = Debug|ARM + {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Debug|x64.ActiveCfg = Debug|x64 + {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Debug|x64.Build.0 = Debug|x64 + {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Debug|x86.ActiveCfg = Debug|Win32 + {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Debug|x86.Build.0 = Debug|Win32 + {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Release|ARM.ActiveCfg = Release|ARM + {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Release|ARM.Build.0 = Release|ARM + {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Release|x64.ActiveCfg = Release|x64 + {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Release|x64.Build.0 = Release|x64 + {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Release|x86.ActiveCfg = Release|Win32 + {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Release|x86.Build.0 = Release|Win32 + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|ARM.ActiveCfg = Debug|ARM + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|ARM.Build.0 = Debug|ARM + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|ARM.Deploy.0 = Debug|ARM + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|x64.ActiveCfg = Debug|x64 + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|x64.Build.0 = Debug|x64 + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|x64.Deploy.0 = Debug|x64 + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|x86.ActiveCfg = Debug|Win32 + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|x86.Build.0 = Debug|Win32 + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|x86.Deploy.0 = Debug|Win32 + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|ARM.ActiveCfg = Release|ARM + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|ARM.Build.0 = Release|ARM + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|ARM.Deploy.0 = Release|ARM + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|x64.ActiveCfg = Release|x64 + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|x64.Build.0 = Release|x64 + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|x64.Deploy.0 = Release|x64 + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|x86.ActiveCfg = Release|Win32 + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|x86.Build.0 = Release|Win32 + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|x86.Deploy.0 = Release|Win32 + {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|ARM.ActiveCfg = Debug|Win32 + {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|x64.ActiveCfg = Debug|x64 + {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|x64.Build.0 = Debug|x64 + {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|x86.ActiveCfg = Debug|Win32 + {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|x86.Build.0 = Debug|Win32 + {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|ARM.ActiveCfg = Release|Win32 + {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|x64.ActiveCfg = Release|x64 + {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|x64.Build.0 = Release|x64 + {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|x86.ActiveCfg = Release|Win32 + {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|x86.Build.0 = Release|Win32 + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|ARM.ActiveCfg = Debug|ARM + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|ARM.Build.0 = Debug|ARM + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|ARM.Deploy.0 = Debug|ARM + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|x64.ActiveCfg = Debug|x64 + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|x64.Build.0 = Debug|x64 + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|x64.Deploy.0 = Debug|x64 + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|x86.ActiveCfg = Debug|Win32 + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|x86.Build.0 = Debug|Win32 + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|x86.Deploy.0 = Debug|Win32 + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|ARM.ActiveCfg = Release|ARM + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|ARM.Build.0 = Release|ARM + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|ARM.Deploy.0 = Release|ARM + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|x64.ActiveCfg = Release|x64 + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|x64.Build.0 = Release|x64 + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|x64.Deploy.0 = Release|x64 + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|x86.ActiveCfg = Release|Win32 + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|x86.Build.0 = Release|Win32 + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|x86.Deploy.0 = Release|Win32 + {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|ARM.ActiveCfg = Debug|Win32 + {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|x64.ActiveCfg = Debug|x64 + {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|x64.Build.0 = Debug|x64 + {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|x86.ActiveCfg = Debug|Win32 + {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|x86.Build.0 = Debug|Win32 + {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|ARM.ActiveCfg = Release|Win32 + {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|x64.ActiveCfg = Release|x64 + {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|x64.Build.0 = Release|x64 + {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|x86.ActiveCfg = Release|Win32 + {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|x86.Build.0 = Release|Win32 + {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|ARM.ActiveCfg = Debug|Win32 + {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|x64.ActiveCfg = Debug|x64 + {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|x64.Build.0 = Debug|x64 + {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|x86.ActiveCfg = Debug|Win32 + {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|x86.Build.0 = Debug|Win32 + {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|ARM.ActiveCfg = Release|Win32 + {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|x64.ActiveCfg = Release|x64 + {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|x64.Build.0 = Release|x64 + {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|x86.ActiveCfg = Release|Win32 + {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|x86.Build.0 = Release|Win32 + {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|ARM.ActiveCfg = Debug|Win32 + {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|x64.ActiveCfg = Debug|x64 + {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|x64.Build.0 = Debug|x64 + {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|x86.ActiveCfg = Debug|Win32 + {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|x86.Build.0 = Debug|Win32 + {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|ARM.ActiveCfg = Release|Win32 + {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x64.ActiveCfg = Release|x64 + {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x64.Build.0 = Release|x64 + {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x86.ActiveCfg = Release|Win32 + {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {65951C40-A332-4B54-89C2-7CDAF30D5F66} = {92944FCF-7E50-41FD-8A99-DD6869F9AEA5} + {594DCB5F-07E3-4084-A2CE-268611FA629F} = {92944FCF-7E50-41FD-8A99-DD6869F9AEA5} + {3D5908F7-7673-4229-BC46-2007A7AF9CAE} = {92944FCF-7E50-41FD-8A99-DD6869F9AEA5} + {F40F4804-50F9-4257-8D74-B9CBB19AC4C3} = {92944FCF-7E50-41FD-8A99-DD6869F9AEA5} + {0A9BA181-7876-4B3D-A5E0-EE673FA51C05} = {92944FCF-7E50-41FD-8A99-DD6869F9AEA5} + {1014C621-BC2D-4813-B8C1-6D83AD6F9249} = {92944FCF-7E50-41FD-8A99-DD6869F9AEA5} + {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9} = {92944FCF-7E50-41FD-8A99-DD6869F9AEA5} + {F03BEE03-BEFB-4B17-A774-D9C8246530D4} = {EF775754-D70A-4611-A00C-F49F224FD236} + {2887A786-B818-4B3D-94EF-21EFD6AFDC22} = {EF775754-D70A-4611-A00C-F49F224FD236} + {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654} = {EF775754-D70A-4611-A00C-F49F224FD236} + {850CCB95-CFA8-4E41-9D1D-387C0C186740} = {EF775754-D70A-4611-A00C-F49F224FD236} + {43DE4DF3-ACAA-429E-B260-CC6D4FE82658} = {EF775754-D70A-4611-A00C-F49F224FD236} + {FFBFD6C1-B525-4D35-AB64-A2FE9460B147} = {EF775754-D70A-4611-A00C-F49F224FD236} + {B8D3F85B-DA71-4ACA-87BA-10FED681DC79} = {EF775754-D70A-4611-A00C-F49F224FD236} + {84350CD1-D406-4A4F-9571-261CA46D77C5} = {EF775754-D70A-4611-A00C-F49F224FD236} + {830B6E2F-9224-41D1-B9C7-A51FC78B00C7} = {EF775754-D70A-4611-A00C-F49F224FD236} + {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D} = {EF775754-D70A-4611-A00C-F49F224FD236} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5782CB9E-B335-4D07-A195-717BF4093536} + EndGlobalSection +EndGlobal From 801943b888c8f3d8c167fec749c1a36ddfaf05ad Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 18 Oct 2017 23:06:37 -0700 Subject: [PATCH 128/438] Add Generated Files to gitignore. Normalize BingRequest141. --- .gitignore | 2 ++ .../BingRequest/BingRequest141/BingRequest141.vcxproj | 10 +--------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index cbc754231e..49f694a391 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,5 @@ build.*/ docs/ # ignore NuGet artifacts .nuget/ + +Generated Files/ \ No newline at end of file diff --git a/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj b/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj index 215c686f1e..04ca9dee54 100644 --- a/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj +++ b/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj @@ -55,15 +55,7 @@ v141
- - - $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), build.root)) - $(BuildRoot)\Binaries\$(Platform)\$(Configuration)\ - $(OutputPath) - $(BuildRoot)\Release\src - $(BuildRoot)\Release\include - + From 6f291dd16b244e9d02e54a903f7082f462505fd7 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 18 Oct 2017 23:15:47 -0700 Subject: [PATCH 129/438] Remove v120 MSBuild files. Use CMake instead. --- Release/dirs.proj | 16 - .../BingRequest120.xp.vcxproj | 133 -------- .../BingRequest120.xp.vcxproj.filters | 13 - .../BingRequest120/BingRequest120.vcxproj | 143 -------- .../BingRequest120.vcxproj.filters | 13 - Release/samples/BingRequest/dirs.proj | 15 - .../BlackJack_Client120.vcxproj | 148 -------- .../BlackJack_Client120.vcxproj.filters | 33 -- .../BlackJack/BlackJack_Client/dirs.proj | 11 - .../BlackJack_Server120.vcxproj | 154 --------- .../BlackJack_Server120.vcxproj.filters | 41 --- .../BlackJack/BlackJack_Server/dirs.proj | 11 - .../BlackJack_UIClient120.vcxproj | 182 ---------- Release/samples/BlackJack/dirs.proj | 16 - .../CasaLens/CasaLens120/CasaLens120.vcxproj | 168 --------- .../CasaLens120/CasaLens120.vcxproj.filters | 33 -- Release/samples/CasaLens/dirs.proj | 11 - .../FacebookDemo/FacebookDemo120.vcxproj | 184 ---------- Release/samples/FacebookDemo/dirs.proj | 11 - .../samples/OAuth2Live/OAuth2Live120.vcxproj | 188 ---------- Release/samples/OAuth2Live/dirs.proj | 11 - .../Oauth1Client120/Oauth1Client120.vcxproj | 205 ----------- .../Oauth1Client120.vcxproj.filters | 33 -- Release/samples/Oauth1Client/dirs.proj | 11 - .../Oauth2Client120/Oauth2Client120.sln | 34 -- .../Oauth2Client120/Oauth2Client120.vcxproj | 205 ----------- .../Oauth2Client120.vcxproj.filters | 33 -- Release/samples/Oauth2Client/dirs.proj | 11 - .../SearchFile120/SearchFile120.vcxproj | 133 -------- .../SearchFile120.vcxproj.filters | 13 - Release/samples/SearchFile/dirs.proj | 11 - .../WindowsLiveAuth120.vcxproj | 190 ----------- Release/samples/WindowsLiveAuth/dirs.proj | 15 - Release/samples/dirs.proj | 24 -- .../vs12.winrt/casablanca120.winrt.vcxproj | 68 ---- .../vs12.wp81/casablanca120.wp81.vcxproj | 68 ---- .../vs12.wps81/casablanca120.wps81.vcxproj | 66 ---- .../casablanca120.xp.static.vcxproj | 109 ------ .../src/build/vs12.xp.static/packages.config | 13 - .../build/vs12.xp/casablanca120.xp.vcxproj | 83 ----- Release/src/build/vs12.xp/packages.config | 13 - Release/src/build/vs12/casablanca120.vcxproj | 79 ----- Release/src/build/vs12/packages.config | 13 - Release/src/dirs.proj | 31 -- Release/tests/common/TestRunner/dirs.proj | 25 -- .../vs12.winrt/TestRunner120.winrt.vcxproj | 250 -------------- .../TestRunner120.winrt.vcxproj.filters | 24 -- .../TestRunner/vs12/TestRunner120.vcxproj | 250 -------------- .../vs12/TestRunner120.vcxproj.filters | 24 -- Release/tests/common/UnitTestpp/dirs.proj | 26 -- .../vs12.winrt/UnitTestpp120.winrt.vcxproj | 263 -------------- .../UnitTestpp120.winrt.vcxproj.filters | 159 --------- .../UnitTestpp/vs12/TestUnitTestpp120.vcxproj | 202 ----------- .../vs12/TestUnitTestpp120.vcxproj.filters | 72 ---- .../UnitTestpp/vs12/UnitTestpp120.vcxproj | 228 ------------- .../vs12/UnitTestpp120.vcxproj.filters | 159 --------- Release/tests/common/dirs.proj | 13 - Release/tests/common/utilities/dirs.proj | 25 -- .../CommonUtilities120.winrt.vcxproj | 274 --------------- .../CommonUtilities120.winrt.vcxproj.filters | 33 -- .../vs12.xp/CommonUtilities120.xp.vcxproj | 150 -------- .../utilities/vs12/CommonUtilities120.vcxproj | 203 ----------- .../vs12/CommonUtilities120.vcxproj.filters | 33 -- Release/tests/dirs.proj | 12 - Release/tests/functional/dirs.proj | 18 - .../http/client/AuthListener/App.config | 6 - .../http/client/AuthListener/Program.cs | 146 -------- .../AuthListener/Properties/AssemblyInfo.cs | 36 -- .../http/client/AuthListener/dirs.proj | 15 - .../AuthListener/vs12/AuthListener120.csproj | 60 ---- .../tests/functional/http/client/dirs.proj | 22 -- .../HttpClient120_test.winrt.vcxproj | 257 -------------- .../HttpClient120_test.winrt.vcxproj.filters | 87 ----- .../client/vs12/HttpClient120_test.vcxproj | 234 ------------- .../vs12/HttpClient120_test.vcxproj.filters | 88 ----- Release/tests/functional/http/dirs.proj | 13 - .../tests/functional/http/listener/dirs.proj | 15 - .../vs12/HttpListener120_test.vcxproj | 236 ------------- .../vs12/HttpListener120_test.vcxproj.filters | 66 ---- .../tests/functional/http/utilities/dirs.proj | 24 -- .../HttpTestUtilities120.winrt.vcxproj | 246 -------------- ...HttpTestUtilities120.winrt.vcxproj.filters | 51 --- .../vs12/HttpTestUtilities120.vcxproj | 218 ------------ .../vs12/HttpTestUtilities120.vcxproj.filters | 51 --- Release/tests/functional/json/dirs.proj | 26 -- .../vs12.winrt/JSON120_test.winrt.vcxproj | 234 ------------- .../JSON120_test.winrt.vcxproj.filters | 42 --- .../json/vs12.xp/JSON120_test.xp.vcxproj | 151 -------- .../functional/json/vs12/JSON120_test.vcxproj | 207 ----------- .../json/vs12/JSON120_test.vcxproj.filters | 44 --- .../functional/misc/atl_headers/dirs.proj | 10 - .../atl_headers/vs12/header_test120.vcxproj | 173 ---------- .../vs12/header_test120.vcxproj.filters | 32 -- Release/tests/functional/misc/dirs.proj | 16 - .../tests/functional/misc/version/dirs.proj | 11 - Release/tests/functional/pplx/dirs.proj | 11 - .../tests/functional/pplx/pplx_test/dirs.proj | 26 -- .../vs12.winrt/pplx120_test.winrt.vcxproj | 228 ------------- .../pplx_test/vs12.xp/pplx120_test.xp.vcxproj | 158 --------- .../pplx/pplx_test/vs12/pplx120_test.vcxproj | 216 ------------ Release/tests/functional/streams/dirs.proj | 26 -- .../vs12.winrt/streams120_test.winrt.vcxproj | 246 -------------- .../streams120_test.winrt.vcxproj.filters | 45 --- .../vs12.xp/streams120_test.xp.vcxproj | 163 --------- .../streams/vs12/streams120_test.vcxproj | 216 ------------ .../vs12/streams120_test.vcxproj.filters | 43 --- Release/tests/functional/uri/dirs.proj | 26 -- .../URI120_test.winrt.vcxproj.filters | 57 ---- .../uri/vs12.winrt/Uri120_test.winrt.vcxproj | 234 ------------- .../uri/vs12.xp/Uri120_test.xp.vcxproj | 155 --------- .../functional/uri/vs12/Uri120_test.vcxproj | 208 ------------ .../uri/vs12/Uri120_test.vcxproj.filters | 59 ---- Release/tests/functional/utils/dirs.proj | 26 -- .../vs12.winrt/Utils120_test.winrt.vcxproj | 229 ------------- .../Utils120_test.winrt.vcxproj.filters | 36 -- .../utils/vs12.xp/Utils120_test.xp.vcxproj | 151 -------- .../utils/vs12/Utils120_test.vcxproj | 202 ----------- .../utils/vs12/Utils120_test.vcxproj.filters | 38 --- .../functional/websockets/client/dirs.proj | 26 -- .../websocketsclient120_test.winrt.vcxproj | 179 ---------- .../websocketsclient120_test.xp.vcxproj | 123 ------- .../vs12/websocketsclient120_test.vcxproj | 129 ------- Release/tests/functional/websockets/dirs.proj | 12 - .../functional/websockets/utilities/dirs.proj | 26 -- ...websockets_test_utilities120.winrt.vcxproj | 178 ---------- .../websockets_test_utilities120.xp.vcxproj | 132 ------- .../websockets/utilities/vs12/packages.config | 7 - .../vs12/websockets_test_utilities120.vcxproj | 157 --------- cpprestsdk120.sln | 321 ------------------ setup_ps_env_VS2013.ps1 | 22 -- setup_ps_env_VS2015.ps1 | 17 - 131 files changed, 12384 deletions(-) delete mode 100644 Release/dirs.proj delete mode 100644 Release/samples/BingRequest/BingRequest120.xp/BingRequest120.xp.vcxproj delete mode 100644 Release/samples/BingRequest/BingRequest120.xp/BingRequest120.xp.vcxproj.filters delete mode 100644 Release/samples/BingRequest/BingRequest120/BingRequest120.vcxproj delete mode 100644 Release/samples/BingRequest/BingRequest120/BingRequest120.vcxproj.filters delete mode 100644 Release/samples/BingRequest/dirs.proj delete mode 100644 Release/samples/BlackJack/BlackJack_Client/BlackJack_Client120/BlackJack_Client120.vcxproj delete mode 100644 Release/samples/BlackJack/BlackJack_Client/BlackJack_Client120/BlackJack_Client120.vcxproj.filters delete mode 100644 Release/samples/BlackJack/BlackJack_Client/dirs.proj delete mode 100644 Release/samples/BlackJack/BlackJack_Server/BlackJack_Server120/BlackJack_Server120.vcxproj delete mode 100644 Release/samples/BlackJack/BlackJack_Server/BlackJack_Server120/BlackJack_Server120.vcxproj.filters delete mode 100644 Release/samples/BlackJack/BlackJack_Server/dirs.proj delete mode 100644 Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient120.vcxproj delete mode 100644 Release/samples/BlackJack/dirs.proj delete mode 100644 Release/samples/CasaLens/CasaLens120/CasaLens120.vcxproj delete mode 100644 Release/samples/CasaLens/CasaLens120/CasaLens120.vcxproj.filters delete mode 100644 Release/samples/CasaLens/dirs.proj delete mode 100644 Release/samples/FacebookDemo/FacebookDemo120.vcxproj delete mode 100644 Release/samples/FacebookDemo/dirs.proj delete mode 100644 Release/samples/OAuth2Live/OAuth2Live120.vcxproj delete mode 100644 Release/samples/OAuth2Live/dirs.proj delete mode 100644 Release/samples/Oauth1Client/Oauth1Client120/Oauth1Client120.vcxproj delete mode 100644 Release/samples/Oauth1Client/Oauth1Client120/Oauth1Client120.vcxproj.filters delete mode 100644 Release/samples/Oauth1Client/dirs.proj delete mode 100644 Release/samples/Oauth2Client/Oauth2Client120/Oauth2Client120.sln delete mode 100644 Release/samples/Oauth2Client/Oauth2Client120/Oauth2Client120.vcxproj delete mode 100644 Release/samples/Oauth2Client/Oauth2Client120/Oauth2Client120.vcxproj.filters delete mode 100644 Release/samples/Oauth2Client/dirs.proj delete mode 100644 Release/samples/SearchFile/SearchFile120/SearchFile120.vcxproj delete mode 100644 Release/samples/SearchFile/SearchFile120/SearchFile120.vcxproj.filters delete mode 100644 Release/samples/SearchFile/dirs.proj delete mode 100644 Release/samples/WindowsLiveAuth/WindowsLiveAuth120.vcxproj delete mode 100644 Release/samples/WindowsLiveAuth/dirs.proj delete mode 100644 Release/samples/dirs.proj delete mode 100644 Release/src/build/vs12.winrt/casablanca120.winrt.vcxproj delete mode 100644 Release/src/build/vs12.wp81/casablanca120.wp81.vcxproj delete mode 100644 Release/src/build/vs12.wps81/casablanca120.wps81.vcxproj delete mode 100644 Release/src/build/vs12.xp.static/casablanca120.xp.static.vcxproj delete mode 100644 Release/src/build/vs12.xp.static/packages.config delete mode 100644 Release/src/build/vs12.xp/casablanca120.xp.vcxproj delete mode 100644 Release/src/build/vs12.xp/packages.config delete mode 100644 Release/src/build/vs12/casablanca120.vcxproj delete mode 100644 Release/src/build/vs12/packages.config delete mode 100644 Release/src/dirs.proj delete mode 100644 Release/tests/common/TestRunner/dirs.proj delete mode 100644 Release/tests/common/TestRunner/vs12.winrt/TestRunner120.winrt.vcxproj delete mode 100644 Release/tests/common/TestRunner/vs12.winrt/TestRunner120.winrt.vcxproj.filters delete mode 100644 Release/tests/common/TestRunner/vs12/TestRunner120.vcxproj delete mode 100644 Release/tests/common/TestRunner/vs12/TestRunner120.vcxproj.filters delete mode 100644 Release/tests/common/UnitTestpp/dirs.proj delete mode 100644 Release/tests/common/UnitTestpp/vs12.winrt/UnitTestpp120.winrt.vcxproj delete mode 100644 Release/tests/common/UnitTestpp/vs12.winrt/UnitTestpp120.winrt.vcxproj.filters delete mode 100644 Release/tests/common/UnitTestpp/vs12/TestUnitTestpp120.vcxproj delete mode 100644 Release/tests/common/UnitTestpp/vs12/TestUnitTestpp120.vcxproj.filters delete mode 100644 Release/tests/common/UnitTestpp/vs12/UnitTestpp120.vcxproj delete mode 100644 Release/tests/common/UnitTestpp/vs12/UnitTestpp120.vcxproj.filters delete mode 100644 Release/tests/common/dirs.proj delete mode 100644 Release/tests/common/utilities/dirs.proj delete mode 100644 Release/tests/common/utilities/vs12.winrt/CommonUtilities120.winrt.vcxproj delete mode 100644 Release/tests/common/utilities/vs12.winrt/CommonUtilities120.winrt.vcxproj.filters delete mode 100644 Release/tests/common/utilities/vs12.xp/CommonUtilities120.xp.vcxproj delete mode 100644 Release/tests/common/utilities/vs12/CommonUtilities120.vcxproj delete mode 100644 Release/tests/common/utilities/vs12/CommonUtilities120.vcxproj.filters delete mode 100644 Release/tests/dirs.proj delete mode 100644 Release/tests/functional/dirs.proj delete mode 100644 Release/tests/functional/http/client/AuthListener/App.config delete mode 100644 Release/tests/functional/http/client/AuthListener/Program.cs delete mode 100644 Release/tests/functional/http/client/AuthListener/Properties/AssemblyInfo.cs delete mode 100644 Release/tests/functional/http/client/AuthListener/dirs.proj delete mode 100644 Release/tests/functional/http/client/AuthListener/vs12/AuthListener120.csproj delete mode 100644 Release/tests/functional/http/client/dirs.proj delete mode 100644 Release/tests/functional/http/client/vs12.winrt/HttpClient120_test.winrt.vcxproj delete mode 100644 Release/tests/functional/http/client/vs12.winrt/HttpClient120_test.winrt.vcxproj.filters delete mode 100644 Release/tests/functional/http/client/vs12/HttpClient120_test.vcxproj delete mode 100644 Release/tests/functional/http/client/vs12/HttpClient120_test.vcxproj.filters delete mode 100644 Release/tests/functional/http/dirs.proj delete mode 100644 Release/tests/functional/http/listener/dirs.proj delete mode 100644 Release/tests/functional/http/listener/vs12/HttpListener120_test.vcxproj delete mode 100644 Release/tests/functional/http/listener/vs12/HttpListener120_test.vcxproj.filters delete mode 100644 Release/tests/functional/http/utilities/dirs.proj delete mode 100644 Release/tests/functional/http/utilities/vs12.winrt/HttpTestUtilities120.winrt.vcxproj delete mode 100644 Release/tests/functional/http/utilities/vs12.winrt/HttpTestUtilities120.winrt.vcxproj.filters delete mode 100644 Release/tests/functional/http/utilities/vs12/HttpTestUtilities120.vcxproj delete mode 100644 Release/tests/functional/http/utilities/vs12/HttpTestUtilities120.vcxproj.filters delete mode 100644 Release/tests/functional/json/dirs.proj delete mode 100644 Release/tests/functional/json/vs12.winrt/JSON120_test.winrt.vcxproj delete mode 100644 Release/tests/functional/json/vs12.winrt/JSON120_test.winrt.vcxproj.filters delete mode 100644 Release/tests/functional/json/vs12.xp/JSON120_test.xp.vcxproj delete mode 100644 Release/tests/functional/json/vs12/JSON120_test.vcxproj delete mode 100644 Release/tests/functional/json/vs12/JSON120_test.vcxproj.filters delete mode 100644 Release/tests/functional/misc/atl_headers/dirs.proj delete mode 100644 Release/tests/functional/misc/atl_headers/vs12/header_test120.vcxproj delete mode 100644 Release/tests/functional/misc/atl_headers/vs12/header_test120.vcxproj.filters delete mode 100644 Release/tests/functional/misc/dirs.proj delete mode 100644 Release/tests/functional/misc/version/dirs.proj delete mode 100644 Release/tests/functional/pplx/dirs.proj delete mode 100644 Release/tests/functional/pplx/pplx_test/dirs.proj delete mode 100644 Release/tests/functional/pplx/pplx_test/vs12.winrt/pplx120_test.winrt.vcxproj delete mode 100644 Release/tests/functional/pplx/pplx_test/vs12.xp/pplx120_test.xp.vcxproj delete mode 100644 Release/tests/functional/pplx/pplx_test/vs12/pplx120_test.vcxproj delete mode 100644 Release/tests/functional/streams/dirs.proj delete mode 100644 Release/tests/functional/streams/vs12.winrt/streams120_test.winrt.vcxproj delete mode 100644 Release/tests/functional/streams/vs12.winrt/streams120_test.winrt.vcxproj.filters delete mode 100644 Release/tests/functional/streams/vs12.xp/streams120_test.xp.vcxproj delete mode 100644 Release/tests/functional/streams/vs12/streams120_test.vcxproj delete mode 100644 Release/tests/functional/streams/vs12/streams120_test.vcxproj.filters delete mode 100644 Release/tests/functional/uri/dirs.proj delete mode 100644 Release/tests/functional/uri/vs12.winrt/URI120_test.winrt.vcxproj.filters delete mode 100644 Release/tests/functional/uri/vs12.winrt/Uri120_test.winrt.vcxproj delete mode 100644 Release/tests/functional/uri/vs12.xp/Uri120_test.xp.vcxproj delete mode 100644 Release/tests/functional/uri/vs12/Uri120_test.vcxproj delete mode 100644 Release/tests/functional/uri/vs12/Uri120_test.vcxproj.filters delete mode 100644 Release/tests/functional/utils/dirs.proj delete mode 100644 Release/tests/functional/utils/vs12.winrt/Utils120_test.winrt.vcxproj delete mode 100644 Release/tests/functional/utils/vs12.winrt/Utils120_test.winrt.vcxproj.filters delete mode 100644 Release/tests/functional/utils/vs12.xp/Utils120_test.xp.vcxproj delete mode 100644 Release/tests/functional/utils/vs12/Utils120_test.vcxproj delete mode 100644 Release/tests/functional/utils/vs12/Utils120_test.vcxproj.filters delete mode 100644 Release/tests/functional/websockets/client/dirs.proj delete mode 100644 Release/tests/functional/websockets/client/vs12.winrt/websocketsclient120_test.winrt.vcxproj delete mode 100644 Release/tests/functional/websockets/client/vs12.xp/websocketsclient120_test.xp.vcxproj delete mode 100644 Release/tests/functional/websockets/client/vs12/websocketsclient120_test.vcxproj delete mode 100644 Release/tests/functional/websockets/dirs.proj delete mode 100644 Release/tests/functional/websockets/utilities/dirs.proj delete mode 100644 Release/tests/functional/websockets/utilities/vs12.winrt/websockets_test_utilities120.winrt.vcxproj delete mode 100644 Release/tests/functional/websockets/utilities/vs12.xp/websockets_test_utilities120.xp.vcxproj delete mode 100644 Release/tests/functional/websockets/utilities/vs12/packages.config delete mode 100644 Release/tests/functional/websockets/utilities/vs12/websockets_test_utilities120.vcxproj delete mode 100644 cpprestsdk120.sln delete mode 100644 setup_ps_env_VS2013.ps1 delete mode 100644 setup_ps_env_VS2015.ps1 diff --git a/Release/dirs.proj b/Release/dirs.proj deleted file mode 100644 index bdbd321a8d..0000000000 --- a/Release/dirs.proj +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/Release/samples/BingRequest/BingRequest120.xp/BingRequest120.xp.vcxproj b/Release/samples/BingRequest/BingRequest120.xp/BingRequest120.xp.vcxproj deleted file mode 100644 index 67d605f1f9..0000000000 --- a/Release/samples/BingRequest/BingRequest120.xp/BingRequest120.xp.vcxproj +++ /dev/null @@ -1,133 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - Application - true - NotSet - v120_xp - - - Application - true - NotSet - v120_xp - - - Application - false - true - NotSet - v120_xp - - - Application - false - true - NotSet - v120_xp - - - - - - - /bigobj %(AdditionalOptions) - NotUsing - Disabled - CPPREST_TARGET_XP;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - Disabled - CPPREST_TARGET_XP;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - MaxSpeed - true - true - CPPREST_TARGET_XP;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - MaxSpeed - true - true - CPPREST_TARGET_XP;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - - - - {15f3b200-1aed-4b57-af37-b21cd67914b1} - - - - \ No newline at end of file diff --git a/Release/samples/BingRequest/BingRequest120.xp/BingRequest120.xp.vcxproj.filters b/Release/samples/BingRequest/BingRequest120.xp/BingRequest120.xp.vcxproj.filters deleted file mode 100644 index cee450afc2..0000000000 --- a/Release/samples/BingRequest/BingRequest120.xp/BingRequest120.xp.vcxproj.filters +++ /dev/null @@ -1,13 +0,0 @@ - - - - - {786631e0-badc-4b3f-bd98-9b13e6a8e5f8} - - - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/BingRequest/BingRequest120/BingRequest120.vcxproj b/Release/samples/BingRequest/BingRequest120/BingRequest120.vcxproj deleted file mode 100644 index 981088f76d..0000000000 --- a/Release/samples/BingRequest/BingRequest120/BingRequest120.vcxproj +++ /dev/null @@ -1,143 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - Application - true - NotSet - v120 - - - Application - true - NotSet - v120 - - - Application - false - true - NotSet - v120 - - - Application - false - true - NotSet - v120 - - - - - - $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), build.root)) - $(BuildRoot)\Binaries\$(Platform)\$(Configuration)\ - $(OutputPath) - $(BuildRoot)\Release\src - $(BuildRoot)\Release\include - - - - - - /bigobj %(AdditionalOptions) - NotUsing - Disabled - WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - Disabled - WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} - - - - - - - \ No newline at end of file diff --git a/Release/samples/BingRequest/BingRequest120/BingRequest120.vcxproj.filters b/Release/samples/BingRequest/BingRequest120/BingRequest120.vcxproj.filters deleted file mode 100644 index b78f1994bb..0000000000 --- a/Release/samples/BingRequest/BingRequest120/BingRequest120.vcxproj.filters +++ /dev/null @@ -1,13 +0,0 @@ - - - - - {bc214923-f806-44a3-abd4-08a1aa1a9b3b} - - - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/BingRequest/dirs.proj b/Release/samples/BingRequest/dirs.proj deleted file mode 100644 index 41aac664db..0000000000 --- a/Release/samples/BingRequest/dirs.proj +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client120/BlackJack_Client120.vcxproj b/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client120/BlackJack_Client120.vcxproj deleted file mode 100644 index 004ac5e463..0000000000 --- a/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client120/BlackJack_Client120.vcxproj +++ /dev/null @@ -1,148 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {830b6e2f-9224-41d1-b9c7-a51fc78b00c7} - Win32Proj - BlackJack_Client - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - Application - true - NotSet - v120 - - - Application - true - NotSet - v120 - - - Application - false - true - NotSet - v120 - - - Application - false - true - NotSet - v120 - - - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);..\..\BlackJack_Server;$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);..\..\BlackJack_Server;$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);..\..\BlackJack_Server;$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);..\..\BlackJack_Server;$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - - - - - - Create - Create - Create - Create - - - - - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} - - - - diff --git a/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client120/BlackJack_Client120.vcxproj.filters b/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client120/BlackJack_Client120.vcxproj.filters deleted file mode 100644 index 127018be70..0000000000 --- a/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client120/BlackJack_Client120.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_Client/dirs.proj b/Release/samples/BlackJack/BlackJack_Client/dirs.proj deleted file mode 100644 index 873f38e386..0000000000 --- a/Release/samples/BlackJack/BlackJack_Client/dirs.proj +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server120/BlackJack_Server120.vcxproj b/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server120/BlackJack_Server120.vcxproj deleted file mode 100644 index 87ec496b5e..0000000000 --- a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server120/BlackJack_Server120.vcxproj +++ /dev/null @@ -1,154 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {84350cd1-d406-4a4f-9571-261ca46d77c5} - Win32Proj - BlackJack_Server - SAK - SAK - SAK - $(VCTargetsPath12) - SAK - - - - Application - true - NotSet - v120 - - - Application - true - NotSet - v120 - - - Application - false - true - NotSet - v120 - - - Application - false - true - NotSet - v120 - - - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} - - - - \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server120/BlackJack_Server120.vcxproj.filters b/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server120/BlackJack_Server120.vcxproj.filters deleted file mode 100644 index a0eae4c8d1..0000000000 --- a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server120/BlackJack_Server120.vcxproj.filters +++ /dev/null @@ -1,41 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_Server/dirs.proj b/Release/samples/BlackJack/BlackJack_Server/dirs.proj deleted file mode 100644 index 2514717ba1..0000000000 --- a/Release/samples/BlackJack/BlackJack_Server/dirs.proj +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient120.vcxproj b/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient120.vcxproj deleted file mode 100644 index 00535c0cdb..0000000000 --- a/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient120.vcxproj +++ /dev/null @@ -1,182 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {b8d3f85b-da71-4aca-87ba-10fed681dc79} - BlackJack_UIClient - en-US - 12.0 - true - SAK - SAK - SAK - SAK - Windows Store - 8.1 - - - - Application - true - v120 - - - Application - true - v120 - - - Application - true - v120 - - - Application - false - true - v120 - - - Application - false - true - v120 - - - Application - false - true - v120 - - - - - - - - - - - - - - - - - - - - - - - - - - BlackJack_UIClient_TemporaryKey.pfx - - - - pch.h - WIN32;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);%(AdditionalIncludeDirectories) - 4100;4267;4450;4453;4702;%(DisableSpecificWarnings) - - - - $(OutDir)\$(MSBuildProjectName)\ - F21E91BD711D606106CD99CE5C2E090FD822956F - - - - CardShape.xaml - - - - App.xaml - - - Player.xaml - - - PlayingTable.xaml - - - - - Designer - - - - Designer - - - - - - - Designer - - - - - - - - - - - - - - App.xaml - - - CardShape.xaml - - - Create - Create - Create - Create - Create - Create - - - Player.xaml - - - PlayingTable.xaml - - - - - {198ED804-2655-4D92-8104-C220E3EA9452} - - - - \ No newline at end of file diff --git a/Release/samples/BlackJack/dirs.proj b/Release/samples/BlackJack/dirs.proj deleted file mode 100644 index 01cd2b9ca6..0000000000 --- a/Release/samples/BlackJack/dirs.proj +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/Release/samples/CasaLens/CasaLens120/CasaLens120.vcxproj b/Release/samples/CasaLens/CasaLens120/CasaLens120.vcxproj deleted file mode 100644 index 695a518dfb..0000000000 --- a/Release/samples/CasaLens/CasaLens120/CasaLens120.vcxproj +++ /dev/null @@ -1,168 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - Application - true - NotSet - v120 - - - Application - true - NotSet - v120 - - - Application - false - true - NotSet - v120 - - - Application - false - true - NotSet - v120 - - - - - - - /bigobj -Zm140 %(AdditionalOptions) - Use - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj -Zm140 %(AdditionalOptions) - Use - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj -Zm140 %(AdditionalOptions) - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - /bigobj -Zm140 %(AdditionalOptions) - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/samples/CasaLens/CasaLens120/CasaLens120.vcxproj.filters b/Release/samples/CasaLens/CasaLens120/CasaLens120.vcxproj.filters deleted file mode 100644 index 3f96e58d5b..0000000000 --- a/Release/samples/CasaLens/CasaLens120/CasaLens120.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - - - - - - {d774ca0e-abc2-480d-a95a-c748cc85c9a3} - - - {35af6514-c88d-44e5-9e0f-97a7e4d93fb6} - - - \ No newline at end of file diff --git a/Release/samples/CasaLens/dirs.proj b/Release/samples/CasaLens/dirs.proj deleted file mode 100644 index 46ff276f1e..0000000000 --- a/Release/samples/CasaLens/dirs.proj +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/Release/samples/FacebookDemo/FacebookDemo120.vcxproj b/Release/samples/FacebookDemo/FacebookDemo120.vcxproj deleted file mode 100644 index c09ba7fb72..0000000000 --- a/Release/samples/FacebookDemo/FacebookDemo120.vcxproj +++ /dev/null @@ -1,184 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658} - FacebookDemo - en-US - 12.0 - true - Windows Store - 8.1 - - - - Application - true - v120 - - - Application - true - v120 - - - Application - true - v120 - - - Application - false - true - v120 - - - Application - false - true - v120 - - - Application - false - true - v120 - - - - - - - FacebookDemo_TemporaryKey.pfx - - - $(OutDir)\$(MSBuildProjectName)\ - A2EB87D9E8F458456834BA935C38BCD7C389022E - - - - /bigobj %(AdditionalOptions) - 4453 - $(MSBuildProjectDirectory);$(CasablancaIncludeDir);$(MSBuildProjectDirectory)\Generated Files;%(AdditionalIncludeDirectories) - - - - - /bigobj %(AdditionalOptions) - 4453 - $(MSBuildProjectDirectory);$(CasablancaIncludeDir);$(MSBuildProjectDirectory)\Generated Files;%(AdditionalIncludeDirectories) - - - - - /bigobj /Zm137 %(AdditionalOptions) - 4453 - $(MSBuildProjectDirectory);$(CasablancaIncludeDir);$(MSBuildProjectDirectory)\Generated Files;%(AdditionalIncludeDirectories) - - - - - /bigobj %(AdditionalOptions) - 4453 - $(MSBuildProjectDirectory);$(CasablancaIncludeDir);$(MSBuildProjectDirectory)\Generated Files;%(AdditionalIncludeDirectories) - - - - - /bigobj %(AdditionalOptions) - 4453 - $(MSBuildProjectDirectory);$(CasablancaIncludeDir);$(MSBuildProjectDirectory)\Generated Files;%(AdditionalIncludeDirectories) - - - - - /bigobj %(AdditionalOptions) - 4453 - $(MSBuildProjectDirectory);$(CasablancaIncludeDir);$(MSBuildProjectDirectory)\Generated Files;%(AdditionalIncludeDirectories) - - - - - - - App.xaml - - - MainPage.xaml - - - - - Designer - - - Designer - - - Designer - - - - - Designer - - - - - - - - - - - - - App.xaml - - - - MainPage.xaml - - - Create - Create - Create - Create - Create - Create - - - - - {198ed804-2655-4d92-8104-c220e3ea9452} - - - - - - \ No newline at end of file diff --git a/Release/samples/FacebookDemo/dirs.proj b/Release/samples/FacebookDemo/dirs.proj deleted file mode 100644 index 4f05c7d418..0000000000 --- a/Release/samples/FacebookDemo/dirs.proj +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/Release/samples/OAuth2Live/OAuth2Live120.vcxproj b/Release/samples/OAuth2Live/OAuth2Live120.vcxproj deleted file mode 100644 index 505d507611..0000000000 --- a/Release/samples/OAuth2Live/OAuth2Live120.vcxproj +++ /dev/null @@ -1,188 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {2887A786-B818-4B3D-94EF-21EFD6AFDC22} - OAuth2Live - en-US - 12.0 - true - Windows Store - 8.1 - - - - Application - true - v120 - - - Application - true - v120 - - - Application - true - v120 - - - Application - false - true - v120 - - - Application - false - true - v120 - - - Application - false - true - v120 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /bigobj /Zm200 %(AdditionalOptions) - 4453 - $(MSBuildProjectDirectory);$(CasablancaIncludeDir);$(MSBuildProjectDirectory)\Generated Files;%(AdditionalIncludeDirectories) - - - - $(OutDir)\$(MSBuildProjectName)\ - - - OAuth2Live_TemporaryKey.pfx - - - - - App.xaml - - - MainPage.xaml - - - - - Designer - - - Designer - - - Designer - - - - - Designer - - - - - - - - - - - - App.xaml - - - MainPage.xaml - - - Create - Create - Create - Create - Create - Create - - - - - {198ed804-2655-4d92-8104-c220e3ea9452} - - - - - - \ No newline at end of file diff --git a/Release/samples/OAuth2Live/dirs.proj b/Release/samples/OAuth2Live/dirs.proj deleted file mode 100644 index 1f8a5de3cf..0000000000 --- a/Release/samples/OAuth2Live/dirs.proj +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/Release/samples/Oauth1Client/Oauth1Client120/Oauth1Client120.vcxproj b/Release/samples/Oauth1Client/Oauth1Client120/Oauth1Client120.vcxproj deleted file mode 100644 index 220d05bd85..0000000000 --- a/Release/samples/Oauth1Client/Oauth1Client120/Oauth1Client120.vcxproj +++ /dev/null @@ -1,205 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {0AA87B6D-FEDD-4435-A68A-789D7C582591} - Win32Proj - Oauth1Client - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - Application - true - NotSet - v120 - - - Application - true - NotSet - v120 - - - Application - true - NotSet - v120 - - - Application - false - true - NotSet - v120 - - - Application - false - true - NotSet - v120 - - - Application - false - true - NotSet - v120 - - - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} - - - - \ No newline at end of file diff --git a/Release/samples/Oauth1Client/Oauth1Client120/Oauth1Client120.vcxproj.filters b/Release/samples/Oauth1Client/Oauth1Client120/Oauth1Client120.vcxproj.filters deleted file mode 100644 index 48d2ebae5f..0000000000 --- a/Release/samples/Oauth1Client/Oauth1Client120/Oauth1Client120.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/Oauth1Client/dirs.proj b/Release/samples/Oauth1Client/dirs.proj deleted file mode 100644 index c82273b693..0000000000 --- a/Release/samples/Oauth1Client/dirs.proj +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/Release/samples/Oauth2Client/Oauth2Client120/Oauth2Client120.sln b/Release/samples/Oauth2Client/Oauth2Client120/Oauth2Client120.sln deleted file mode 100644 index 5d2a398e85..0000000000 --- a/Release/samples/Oauth2Client/Oauth2Client120/Oauth2Client120.sln +++ /dev/null @@ -1,34 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.30110.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Oauth2Client120", "Oauth2Client120.vcxproj", "{62CF690F-9B67-4A86-9CF4-E7CD07D1A342}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|ARM = Debug|ARM - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|ARM = Release|ARM - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {62CF690F-9B67-4A86-9CF4-E7CD07D1A342}.Debug|ARM.ActiveCfg = Debug|ARM - {62CF690F-9B67-4A86-9CF4-E7CD07D1A342}.Debug|ARM.Build.0 = Debug|ARM - {62CF690F-9B67-4A86-9CF4-E7CD07D1A342}.Debug|Win32.ActiveCfg = Debug|Win32 - {62CF690F-9B67-4A86-9CF4-E7CD07D1A342}.Debug|Win32.Build.0 = Debug|Win32 - {62CF690F-9B67-4A86-9CF4-E7CD07D1A342}.Debug|x64.ActiveCfg = Debug|x64 - {62CF690F-9B67-4A86-9CF4-E7CD07D1A342}.Debug|x64.Build.0 = Debug|x64 - {62CF690F-9B67-4A86-9CF4-E7CD07D1A342}.Release|ARM.ActiveCfg = Release|ARM - {62CF690F-9B67-4A86-9CF4-E7CD07D1A342}.Release|ARM.Build.0 = Release|ARM - {62CF690F-9B67-4A86-9CF4-E7CD07D1A342}.Release|Win32.ActiveCfg = Release|Win32 - {62CF690F-9B67-4A86-9CF4-E7CD07D1A342}.Release|Win32.Build.0 = Release|Win32 - {62CF690F-9B67-4A86-9CF4-E7CD07D1A342}.Release|x64.ActiveCfg = Release|x64 - {62CF690F-9B67-4A86-9CF4-E7CD07D1A342}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/Release/samples/Oauth2Client/Oauth2Client120/Oauth2Client120.vcxproj b/Release/samples/Oauth2Client/Oauth2Client120/Oauth2Client120.vcxproj deleted file mode 100644 index 0376c0243a..0000000000 --- a/Release/samples/Oauth2Client/Oauth2Client120/Oauth2Client120.vcxproj +++ /dev/null @@ -1,205 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {09E24B3F-FE75-4FDA-B75B-8CE3C65C8D8A} - Win32Proj - Oauth2Client - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - Application - true - NotSet - v120 - - - Application - true - NotSet - v120 - - - Application - true - NotSet - v120 - - - Application - false - true - NotSet - v120 - - - Application - false - true - NotSet - v120 - - - Application - false - true - NotSet - v120 - - - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} - - - - \ No newline at end of file diff --git a/Release/samples/Oauth2Client/Oauth2Client120/Oauth2Client120.vcxproj.filters b/Release/samples/Oauth2Client/Oauth2Client120/Oauth2Client120.vcxproj.filters deleted file mode 100644 index d11e5aec8b..0000000000 --- a/Release/samples/Oauth2Client/Oauth2Client120/Oauth2Client120.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/Oauth2Client/dirs.proj b/Release/samples/Oauth2Client/dirs.proj deleted file mode 100644 index 484537a0e5..0000000000 --- a/Release/samples/Oauth2Client/dirs.proj +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/Release/samples/SearchFile/SearchFile120/SearchFile120.vcxproj b/Release/samples/SearchFile/SearchFile120/SearchFile120.vcxproj deleted file mode 100644 index 6c747ed8e1..0000000000 --- a/Release/samples/SearchFile/SearchFile120/SearchFile120.vcxproj +++ /dev/null @@ -1,133 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {F03BEE03-BEFB-4B17-A774-D9C8246530D4} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - Application - true - NotSet - v120 - - - Application - true - NotSet - v120 - - - Application - false - true - NotSet - v120 - - - Application - false - true - NotSet - v120 - - - - - - - /bigobj %(AdditionalOptions) - NotUsing - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} - - - - - - - \ No newline at end of file diff --git a/Release/samples/SearchFile/SearchFile120/SearchFile120.vcxproj.filters b/Release/samples/SearchFile/SearchFile120/SearchFile120.vcxproj.filters deleted file mode 100644 index 2794140178..0000000000 --- a/Release/samples/SearchFile/SearchFile120/SearchFile120.vcxproj.filters +++ /dev/null @@ -1,13 +0,0 @@ - - - - - {bc214923-f806-44a3-abd4-08a1aa1a9b3b} - - - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/SearchFile/dirs.proj b/Release/samples/SearchFile/dirs.proj deleted file mode 100644 index 8f7ae1654b..0000000000 --- a/Release/samples/SearchFile/dirs.proj +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/Release/samples/WindowsLiveAuth/WindowsLiveAuth120.vcxproj b/Release/samples/WindowsLiveAuth/WindowsLiveAuth120.vcxproj deleted file mode 100644 index 2efbe5d141..0000000000 --- a/Release/samples/WindowsLiveAuth/WindowsLiveAuth120.vcxproj +++ /dev/null @@ -1,190 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {1c20f771-3131-46e8-805f-aa1fe44165c0} - WindowsLiveAuth - en-US - 12.0 - true - Windows Store - 8.1 - - - - Application - true - v120 - - - Application - true - v120 - - - Application - true - v120 - - - Application - false - true - v120 - - - Application - false - true - v120 - - - Application - false - true - v120 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /bigobj /Zm200 %(AdditionalOptions) - 4453 - $(MSBuildProjectDirectory);$(CasablancaIncludeDir);$(MSBuildProjectDirectory)\Generated Files;%(AdditionalIncludeDirectories) - - - - $(OutDir)\$(MSBuildProjectName)\ - - - WindowsLiveAuth_TemporaryKey.pfx - D3342DAE1EC703934903364490A80C5BB06C929A - - - - - - App.xaml - - - MainPage.xaml - - - - - Designer - - - Designer - - - Designer - - - - - Designer - - - - - - - - - - - - App.xaml - - - MainPage.xaml - - - Create - Create - Create - Create - Create - Create - - - - - {198ed804-2655-4d92-8104-c220e3ea9452} - - - - - - \ No newline at end of file diff --git a/Release/samples/WindowsLiveAuth/dirs.proj b/Release/samples/WindowsLiveAuth/dirs.proj deleted file mode 100644 index 7060c7e4f1..0000000000 --- a/Release/samples/WindowsLiveAuth/dirs.proj +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/Release/samples/dirs.proj b/Release/samples/dirs.proj deleted file mode 100644 index 4abd4ec473..0000000000 --- a/Release/samples/dirs.proj +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/Release/src/build/vs12.winrt/casablanca120.winrt.vcxproj b/Release/src/build/vs12.winrt/casablanca120.winrt.vcxproj deleted file mode 100644 index c7bebcbdea..0000000000 --- a/Release/src/build/vs12.winrt/casablanca120.winrt.vcxproj +++ /dev/null @@ -1,68 +0,0 @@ - - - - - {9AD285A2-301E-47A0-A299-14AD5D4F2758} - Win32Proj - casablanca - en-US - 12.0 - SAK - SAK - SAK - SAK - true - true - DynamicLibrary - v120 - true - false - - $(OutDir)\$(MsBuildProjectName) - Windows Store - 8.1 - cpprestsdk120.winrt - - - - - - - - - - d - - - $(CppRestBaseFileName)120$(DebugFileSuffix)_app_$(CppRestSDKVersionFileSuffix) - - - - WINAPI_FAMILY=WINAPI_PARTITION_APP;_ASYNCRT_EXPORT;_PPLX_EXPORT;_USRDLL;%(PreprocessorDefinitions); - $(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;%(AdditionalIncludeDirectories) - Use - stdafx.h - -Zm250 /bigobj %(AdditionalOptions) - true - - - msxml6.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) - UseLinkTimeCodeGeneration - false - - - - - - - - - copy /Y $(OutDir)\* $(OutDir)..\ - link /edit /appcontainer:no $(OutDir)..\$(TargetName).dll - exit 0 - Copying $(TargetName).winrt binaries to OutDir and removing appcontainer flag - - - \ No newline at end of file diff --git a/Release/src/build/vs12.wp81/casablanca120.wp81.vcxproj b/Release/src/build/vs12.wp81/casablanca120.wp81.vcxproj deleted file mode 100644 index 8123760fa6..0000000000 --- a/Release/src/build/vs12.wp81/casablanca120.wp81.vcxproj +++ /dev/null @@ -1,68 +0,0 @@ - - - - - {E5F8A2F0-F713-4673-A42F-2CC4E8FB171B} - Win32Proj - casablanca - en-US - 12.0 - SAK - SAK - SAK - SAK - true - true - DynamicLibrary - v120_wp81 - true - false - - $(OutDir)\$(MsBuildProjectName) - Windows Phone - 8.1 - cpprestsdk120.wp81 - - - - - - - - - - d - - - $(CppRestBaseFileName)120$(DebugFileSuffix)_wp81_$(CppRestSDKVersionFileSuffix) - - - - WINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP;_ASYNCRT_EXPORT;_PPLX_EXPORT;_USRDLL;%(PreprocessorDefinitions) - $(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;%(AdditionalIncludeDirectories) - Use - stdafx.h - -Zm250 %(AdditionalOptions) - true - - - msxml6.lib;WindowsPhoneCore.lib;RuntimeObject.lib;PhoneAppModelHost.lib;%(AdditionalDependencies) - false - UseLinkTimeCodeGeneration - - - - - - - - - copy /Y $(OutDir)\* $(OutDir)..\ - link /edit /appcontainer:no $(OutDir)..\$(TargetName).dll - exit 0 - Copying $(TargetName).winrt binaries to OutDir and removing appcontainer flag - - - \ No newline at end of file diff --git a/Release/src/build/vs12.wps81/casablanca120.wps81.vcxproj b/Release/src/build/vs12.wps81/casablanca120.wps81.vcxproj deleted file mode 100644 index 7d6d0172a4..0000000000 --- a/Release/src/build/vs12.wps81/casablanca120.wps81.vcxproj +++ /dev/null @@ -1,66 +0,0 @@ - - - - - {C5D88D15-F9F5-48E2-9EF2-BE0B645B9C0D} - Win32Proj - en-US - 12.0 - SAK - SAK - SAK - SAK - true - true - DynamicLibrary - v120 - true - false - - $(OutDir)\$(MsBuildProjectName) - Windows Phone Silverlight - 8.1 - cpprestsdk120.wps81 - - - - - - - - - - d - - - $(CppRestBaseFileName)120$(DebugFileSuffix)_wps81_$(CppRestSDKVersionFileSuffix) - - - - CPPREST_EXCLUDE_WEBSOCKETS;WINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP;_ASYNCRT_EXPORT;_PPLX_EXPORT;_USRDLL;%(PreprocessorDefinitions) - $(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;%(AdditionalIncludeDirectories) - Use - stdafx.h - -Zm250 %(AdditionalOptions) - true - - - msxml6.lib;WindowsPhoneCore.lib;RuntimeObject.lib;PhoneAppModelHost.lib;%(AdditionalDependencies) - false - UseLinkTimeCodeGeneration - - - - - - - - copy /Y $(OutDir)\* $(OutDir)..\ - link /edit /appcontainer:no $(OutDir)..\$(TargetName).dll - exit 0 - Copying $(TargetName).winrt binaries to OutDir and removing appcontainer flag - - - \ No newline at end of file diff --git a/Release/src/build/vs12.xp.static/casablanca120.xp.static.vcxproj b/Release/src/build/vs12.xp.static/casablanca120.xp.static.vcxproj deleted file mode 100644 index 91a91c3134..0000000000 --- a/Release/src/build/vs12.xp.static/casablanca120.xp.static.vcxproj +++ /dev/null @@ -1,109 +0,0 @@ - - - - - - DebugStatic - ARM - - - DebugStatic - Win32 - - - DebugStatic - x64 - - - ReleaseStatic - ARM - - - ReleaseStatic - Win32 - - - ReleaseStatic - x64 - - - - {CF74448D-FE99-4E3C-AFA6-A50F3145BAF3} - Win32Proj - SAK - SAK - SAK - SAK - StaticLibrary - v120_xp - false - true - cpprestsdk120.xp.static - - - - - - - - true - true - true - true - - - - - - - - - - - - - - - d - - - $(CppRestBaseFileName)120$(DebugFileSuffix)_xp_$(CppRestSDKVersionFileSuffix) - 58b07c0c - - - - - - - _NO_ASYNCRTIMP;_WINSOCK_DEPRECATED_NO_WARNINGS;CPPREST_TARGET_XP;_ASYNCRT_EXPORT;_PPLX_EXPORT;WIN32;_MBCS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Use - stdafx.h - -Zm160 /bigobj %(AdditionalOptions) - MultiThreadedDebugDLL - MultiThreadedDLL - true - - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - - - Winhttp.lib;crypt32.lib;%(AdditionalDependencies) - UseLinkTimeCodeGeneration - - - - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file diff --git a/Release/src/build/vs12.xp.static/packages.config b/Release/src/build/vs12.xp.static/packages.config deleted file mode 100644 index 7b1dc6aac0..0000000000 --- a/Release/src/build/vs12.xp.static/packages.config +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/src/build/vs12.xp/casablanca120.xp.vcxproj b/Release/src/build/vs12.xp/casablanca120.xp.vcxproj deleted file mode 100644 index 037e2a439a..0000000000 --- a/Release/src/build/vs12.xp/casablanca120.xp.vcxproj +++ /dev/null @@ -1,83 +0,0 @@ - - - - - {15F3B200-1AED-4B57-AF37-B21CD67914B1} - Win32Proj - SAK - SAK - SAK - SAK - DynamicLibrary - v120_xp - false - true - cpprestsdk120.xp - - - - - - - - true - true - true - true - - - - - - - - - - - - - - - d - - - $(CppRestBaseFileName)120$(DebugFileSuffix)_xp_$(CppRestSDKVersionFileSuffix) - 58b07c0c - - - - - - - _WINSOCK_DEPRECATED_NO_WARNINGS;CPPREST_TARGET_XP;_ASYNCRT_EXPORT;_PPLX_EXPORT;WIN32;_MBCS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Use - stdafx.h - -Zm160 /bigobj %(AdditionalOptions) - MultiThreadedDebugDLL - MultiThreadedDLL - true - - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - - - Winhttp.lib;crypt32.lib;%(AdditionalDependencies) - UseLinkTimeCodeGeneration - - - - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file diff --git a/Release/src/build/vs12.xp/packages.config b/Release/src/build/vs12.xp/packages.config deleted file mode 100644 index 7b1dc6aac0..0000000000 --- a/Release/src/build/vs12.xp/packages.config +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/src/build/vs12/casablanca120.vcxproj b/Release/src/build/vs12/casablanca120.vcxproj deleted file mode 100644 index 5140823890..0000000000 --- a/Release/src/build/vs12/casablanca120.vcxproj +++ /dev/null @@ -1,79 +0,0 @@ - - - - - {01A76234-E6E8-4332-9FE2-1E12C34621BE} - Win32Proj - SAK - SAK - SAK - SAK - DynamicLibrary - v120 - false - false - cpprestsdk120 - - - - - - - - - - - - - - - - - - - d - - - $(CppRestBaseFileName)120$(DebugFileSuffix)_$(CppRestSDKVersionFileSuffix) - 1af61e94 - Unicode - - - - Designer - - - - - _WINSOCK_DEPRECATED_NO_WARNINGS;_ASYNCRT_EXPORT;_PPLX_EXPORT;WIN32;_MBCS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Use - stdafx.h - -Zm160 /bigobj %(AdditionalOptions) - MultiThreadedDebugDLL - MultiThreadedDLL - true - - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - - - Winhttp.lib;httpapi.lib;bcrypt.lib;crypt32.lib;%(AdditionalDependencies) - UseLinkTimeCodeGeneration - - - - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file diff --git a/Release/src/build/vs12/packages.config b/Release/src/build/vs12/packages.config deleted file mode 100644 index 7b1dc6aac0..0000000000 --- a/Release/src/build/vs12/packages.config +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/src/dirs.proj b/Release/src/dirs.proj deleted file mode 100644 index 96b0b6fc94..0000000000 --- a/Release/src/dirs.proj +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/common/TestRunner/dirs.proj b/Release/tests/common/TestRunner/dirs.proj deleted file mode 100644 index b8119ce4e7..0000000000 --- a/Release/tests/common/TestRunner/dirs.proj +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/common/TestRunner/vs12.winrt/TestRunner120.winrt.vcxproj b/Release/tests/common/TestRunner/vs12.winrt/TestRunner120.winrt.vcxproj deleted file mode 100644 index cd7e87d376..0000000000 --- a/Release/tests/common/TestRunner/vs12.winrt/TestRunner120.winrt.vcxproj +++ /dev/null @@ -1,250 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {26009642-9C25-441F-B138-395E14DF2FB6} - Win32Proj - TestRunner - $(VCTargetsPath12) - SAK - SAK - SAK - SAK - - - - Application - true - Unicode - v120 - - - Application - true - Unicode - v120 - - - Application - true - Unicode - v120 - - - Application - false - true - Unicode - v120 - - - Application - false - true - Unicode - v120 - - - Application - false - true - Unicode - v120 - - - - - - - - - - - - - - - - - - - - - - - TestRunner.winrt - - - TestRunner.winrt - - - TestRunner.winrt - - - false - TestRunner.winrt - - - false - TestRunner.winrt - - - false - TestRunner.winrt - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - - NotUsing - Disabled - WINRT_TEST_RUNNER;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - NotUsing - Disabled - WINRT_TEST_RUNNER;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - NotUsing - Disabled - WINRT_TEST_RUNNER;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - NotUsing - MaxSpeed - true - true - WINRT_TEST_RUNNER;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - NotUsing - MaxSpeed - true - true - WINRT_TEST_RUNNER;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - NotUsing - MaxSpeed - true - true - WINRT_TEST_RUNNER;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - {B341AA9C-F38B-4D59-B6B7-8F22491090B7} - - - - - - diff --git a/Release/tests/common/TestRunner/vs12.winrt/TestRunner120.winrt.vcxproj.filters b/Release/tests/common/TestRunner/vs12.winrt/TestRunner120.winrt.vcxproj.filters deleted file mode 100644 index f9fa6c25ca..0000000000 --- a/Release/tests/common/TestRunner/vs12.winrt/TestRunner120.winrt.vcxproj.filters +++ /dev/null @@ -1,24 +0,0 @@ - - - - - Source Files - - - Source Files - - - - - {5e4d32c8-a472-4388-b880-920a7a546fa3} - - - {f05a925c-282c-4424-ae9a-10fe7f88fe47} - - - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/common/TestRunner/vs12/TestRunner120.vcxproj b/Release/tests/common/TestRunner/vs12/TestRunner120.vcxproj deleted file mode 100644 index e4479c83cc..0000000000 --- a/Release/tests/common/TestRunner/vs12/TestRunner120.vcxproj +++ /dev/null @@ -1,250 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {6490C580-DD4A-4F2D-A345-732C5148349F} - Win32Proj - TestRunner - $(VCTargetsPath12) - SAK - SAK - SAK - SAK - - - - Application - true - Unicode - v120 - - - Application - true - Unicode - v120 - - - Application - true - Unicode - v120 - - - Application - false - true - Unicode - v120 - - - Application - false - true - Unicode - v120 - - - Application - false - true - Unicode - v120 - - - - - - - - - - - - - - - - - - - - - - - TestRunner - - - TestRunner - - - TestRunner - - - false - TestRunner - - - false - TestRunner - - - false - TestRunner - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - - NotUsing - Disabled - DESKTOP_TEST_RUNNER;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - NotUsing - Disabled - DESKTOP_TEST_RUNNER;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - NotUsing - Disabled - DESKTOP_TEST_RUNNER;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - NotUsing - MaxSpeed - true - true - DESKTOP_TEST_RUNNER;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - NotUsing - MaxSpeed - true - true - DESKTOP_TEST_RUNNER;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - NotUsing - MaxSpeed - true - true - DESKTOP_TEST_RUNNER;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - {3eb86c0d-432c-4ffc-bad4-8df4efc7d0ff} - - - - - - diff --git a/Release/tests/common/TestRunner/vs12/TestRunner120.vcxproj.filters b/Release/tests/common/TestRunner/vs12/TestRunner120.vcxproj.filters deleted file mode 100644 index f9fa6c25ca..0000000000 --- a/Release/tests/common/TestRunner/vs12/TestRunner120.vcxproj.filters +++ /dev/null @@ -1,24 +0,0 @@ - - - - - Source Files - - - Source Files - - - - - {5e4d32c8-a472-4388-b880-920a7a546fa3} - - - {f05a925c-282c-4424-ae9a-10fe7f88fe47} - - - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/common/UnitTestpp/dirs.proj b/Release/tests/common/UnitTestpp/dirs.proj deleted file mode 100644 index 20495a4cf3..0000000000 --- a/Release/tests/common/UnitTestpp/dirs.proj +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/common/UnitTestpp/vs12.winrt/UnitTestpp120.winrt.vcxproj b/Release/tests/common/UnitTestpp/vs12.winrt/UnitTestpp120.winrt.vcxproj deleted file mode 100644 index 11967444c9..0000000000 --- a/Release/tests/common/UnitTestpp/vs12.winrt/UnitTestpp120.winrt.vcxproj +++ /dev/null @@ -1,263 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {B341AA9C-F38B-4D59-B6B7-8F22491090B7} - Win32Proj - UnitTest - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - $(CasablancaIncludeDir);$(TestRoot)\Common\UnitTestpp\src\;%(AdditionalIncludeDirectories); - Use - - - - - NotUsing - Disabled - UNITTEST_DLL_EXPORT;WIN32;_DEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - $(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - $(VCINSTALLDIR)\lib\store;%(AdditionalLibraryDirectories); - msvcrtd.lib;msvcprtd.lib;vccorlibd.lib;RuntimeObject.lib;%(AdditionalDependencies) - true - - - - - NotUsing - Disabled - UNITTEST_DLL_EXPORT;WIN32;_DEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - $(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - $(VCINSTALLDIR)\lib\store\arm;%(AdditionalLibraryDirectories); - uuid.lib;ole32.lib;msvcrtd.lib;msvcprtd.lib;vccorlibd.lib;RuntimeObject.lib;%(AdditionalDependencies) - true - - - - - NotUsing - Disabled - UNITTEST_DLL_EXPORT;WIN32;_DEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - $(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - $(VCINSTALLDIR)\lib\store\amd64;%(AdditionalLibraryDirectories); - msvcrtd.lib;msvcprtd.lib;vccorlibd.lib;RuntimeObject.lib;%(AdditionalDependencies) - true - - - - - MaxSpeed - NotUsing - true - true - UNITTEST_DLL_EXPORT;WIN32;NDEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - $(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - true - true - $(VCINSTALLDIR)\lib\store;%(AdditionalLibraryDirectories); - msvcrt.lib;msvcprt.lib;vccorlib.lib;RuntimeObject.lib;%(AdditionalDependencies) - true - - - - - MaxSpeed - NotUsing - true - true - UNITTEST_DLL_EXPORT;WIN32;NDEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - $(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - true - true - $(VCINSTALLDIR)\lib\store\arm;%(AdditionalLibraryDirectories); - uuid.lib;ole32.lib;msvcrt.lib;msvcprt.lib;vccorlib.lib;RuntimeObject.lib;%(AdditionalDependencies) - true - - - - - MaxSpeed - NotUsing - true - true - UNITTEST_DLL_EXPORT;WIN32;NDEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - $(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - true - true - $(VCINSTALLDIR)\lib\store\amd64;%(AdditionalLibraryDirectories); - msvcrt.lib;msvcprt.lib;vccorlib.lib;RuntimeObject.lib;%(AdditionalDependencies) - true - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/common/UnitTestpp/vs12.winrt/UnitTestpp120.winrt.vcxproj.filters b/Release/tests/common/UnitTestpp/vs12.winrt/UnitTestpp120.winrt.vcxproj.filters deleted file mode 100644 index 6fd73f9e3b..0000000000 --- a/Release/tests/common/UnitTestpp/vs12.winrt/UnitTestpp120.winrt.vcxproj.filters +++ /dev/null @@ -1,159 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - {640fb93d-0deb-4bc4-a035-5d44d5c2af4b} - - - {b883825b-c6c4-4545-806e-dfe105753ac8} - - - \ No newline at end of file diff --git a/Release/tests/common/UnitTestpp/vs12/TestUnitTestpp120.vcxproj b/Release/tests/common/UnitTestpp/vs12/TestUnitTestpp120.vcxproj deleted file mode 100644 index c77c6b7430..0000000000 --- a/Release/tests/common/UnitTestpp/vs12/TestUnitTestpp120.vcxproj +++ /dev/null @@ -1,202 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {E715BBE6-743D-47C2-8F43-92AA18F6ED19} - Win32Proj - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - TestUnitTestpp120 - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - $(CasablancaIncludeDir);%(AdditionalIncludeDirectories); - - - - - NotUsing - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - - - - - NotUsing - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - - - - - NotUsing - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - - - - - MaxSpeed - NotUsing - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - MaxSpeed - NotUsing - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - MaxSpeed - NotUsing - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - - - - diff --git a/Release/tests/common/UnitTestpp/vs12/TestUnitTestpp120.vcxproj.filters b/Release/tests/common/UnitTestpp/vs12/TestUnitTestpp120.vcxproj.filters deleted file mode 100644 index 44e0743ad6..0000000000 --- a/Release/tests/common/UnitTestpp/vs12/TestUnitTestpp120.vcxproj.filters +++ /dev/null @@ -1,72 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - {420b7d9f-7900-40f3-8aa7-3c800278bc98} - - - {7ddca59d-156c-46f2-af93-4a03f915bbcb} - - - \ No newline at end of file diff --git a/Release/tests/common/UnitTestpp/vs12/UnitTestpp120.vcxproj b/Release/tests/common/UnitTestpp/vs12/UnitTestpp120.vcxproj deleted file mode 100644 index 1c60278851..0000000000 --- a/Release/tests/common/UnitTestpp/vs12/UnitTestpp120.vcxproj +++ /dev/null @@ -1,228 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - Win32Proj - UnitTest - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - UnitTestpp120 - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - $(CasablancaIncludeDir);$(TestRoot)\Common\UnitTestpp\src\;%(AdditionalIncludeDirectories); - Use - - - - - NotUsing - Disabled - UNITTEST_DLL_EXPORT;WIN32;_DEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - - - - - NotUsing - Disabled - UNITTEST_DLL_EXPORT;WIN32;_DEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - - - - - NotUsing - Disabled - UNITTEST_DLL_EXPORT;WIN32;_DEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - - - - - MaxSpeed - NotUsing - true - true - UNITTEST_DLL_EXPORT;WIN32;NDEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - MaxSpeed - NotUsing - true - true - UNITTEST_DLL_EXPORT;WIN32;NDEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - MaxSpeed - NotUsing - true - true - UNITTEST_DLL_EXPORT;WIN32;NDEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/common/UnitTestpp/vs12/UnitTestpp120.vcxproj.filters b/Release/tests/common/UnitTestpp/vs12/UnitTestpp120.vcxproj.filters deleted file mode 100644 index 6fd73f9e3b..0000000000 --- a/Release/tests/common/UnitTestpp/vs12/UnitTestpp120.vcxproj.filters +++ /dev/null @@ -1,159 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - {640fb93d-0deb-4bc4-a035-5d44d5c2af4b} - - - {b883825b-c6c4-4545-806e-dfe105753ac8} - - - \ No newline at end of file diff --git a/Release/tests/common/dirs.proj b/Release/tests/common/dirs.proj deleted file mode 100644 index 51622a29de..0000000000 --- a/Release/tests/common/dirs.proj +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/Release/tests/common/utilities/dirs.proj b/Release/tests/common/utilities/dirs.proj deleted file mode 100644 index 953e655a6e..0000000000 --- a/Release/tests/common/utilities/dirs.proj +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/common/utilities/vs12.winrt/CommonUtilities120.winrt.vcxproj b/Release/tests/common/utilities/vs12.winrt/CommonUtilities120.winrt.vcxproj deleted file mode 100644 index 98a3534883..0000000000 --- a/Release/tests/common/utilities/vs12.winrt/CommonUtilities120.winrt.vcxproj +++ /dev/null @@ -1,274 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {ea2d69a1-55c8-4c15-805e-de7e85872484} - Win32Proj - CommonUtilities120 - SAK - SAK - SAK - SAK - en-US - 12.0 - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - $(VCINSTALLDIR)\lib\store;$(OutDir);%(AdditionalLibraryDirectories); - msvcrtd.lib;msvcprtd.lib;vccorlibd.lib;RuntimeObject.lib;%(AdditionalDependencies) - true - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - $(VCINSTALLDIR)\lib\store\arm;$(OutDir);%(AdditionalLibraryDirectories); - uuid.lib;ole32.lib;msvcrtd.lib;msvcprtd.lib;vccorlibd.lib;RuntimeObject.lib;%(AdditionalDependencies) - true - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - $(VCINSTALLDIR)\lib\store\amd64;$(OutDir);%(AdditionalLibraryDirectories); - msvcrtd.lib;msvcprtd.lib;vccorlibd.lib;RuntimeObject.lib;%(AdditionalDependencies) - true - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - true - true - $(VCINSTALLDIR)\lib\store;$(OutDir);%(AdditionalLibraryDirectories); - msvcrt.lib;msvcprt.lib;vccorlib.lib;RuntimeObject.lib;%(AdditionalDependencies) - true - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - true - true - $(VCINSTALLDIR)\lib\store\arm;$(OutDir);%(AdditionalLibraryDirectories); - uuid.lib;ole32.lib;msvcrt.lib;msvcprt.lib;vccorlib.lib;RuntimeObject.lib;%(AdditionalDependencies) - true - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - true - true - $(VCINSTALLDIR)\lib\store\amd64;$(OutDir);%(AdditionalLibraryDirectories); - msvcrt.lib;msvcprt.lib;vccorlib.lib;RuntimeObject.lib;%(AdditionalDependencies) - true - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - {B341AA9C-F38B-4D59-B6B7-8F22491090B7} - - - {26009642-9C25-441F-B138-395E14DF2FB6} - - - {198ED804-2655-4D92-8104-C220E3EA9452} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/common/utilities/vs12.winrt/CommonUtilities120.winrt.vcxproj.filters b/Release/tests/common/utilities/vs12.winrt/CommonUtilities120.winrt.vcxproj.filters deleted file mode 100644 index 1325242b47..0000000000 --- a/Release/tests/common/utilities/vs12.winrt/CommonUtilities120.winrt.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - {24e13f0e-e0f6-4fe0-922a-5cf7cbe823f4} - - - {ef18a939-f1a3-4e9e-b93a-05826fbae7f6} - - - \ No newline at end of file diff --git a/Release/tests/common/utilities/vs12.xp/CommonUtilities120.xp.vcxproj b/Release/tests/common/utilities/vs12.xp/CommonUtilities120.xp.vcxproj deleted file mode 100644 index 5073a3d364..0000000000 --- a/Release/tests/common/utilities/vs12.xp/CommonUtilities120.xp.vcxproj +++ /dev/null @@ -1,150 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {5AD81270-B089-4E1B-8741-6486F39DE273} - Win32Proj - CommonUtilities120 - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - Create - Create - Create - Create - - - - - - - - - - - {75885703-7f3d-4086-8e60-c60b9b126f7e} - - - {6490c580-dd4a-4f2d-a345-732c5148349f} - - - {3eb86c0d-432c-4ffc-bad4-8df4efc7d0ff} - - - - - - \ No newline at end of file diff --git a/Release/tests/common/utilities/vs12/CommonUtilities120.vcxproj b/Release/tests/common/utilities/vs12/CommonUtilities120.vcxproj deleted file mode 100644 index ae0cf1656c..0000000000 --- a/Release/tests/common/utilities/vs12/CommonUtilities120.vcxproj +++ /dev/null @@ -1,203 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - Win32Proj - CommonUtilities120 - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - Advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - Advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {6490C580-DD4A-4F2D-A345-732C5148349F} - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - - - diff --git a/Release/tests/common/utilities/vs12/CommonUtilities120.vcxproj.filters b/Release/tests/common/utilities/vs12/CommonUtilities120.vcxproj.filters deleted file mode 100644 index 1325242b47..0000000000 --- a/Release/tests/common/utilities/vs12/CommonUtilities120.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - {24e13f0e-e0f6-4fe0-922a-5cf7cbe823f4} - - - {ef18a939-f1a3-4e9e-b93a-05826fbae7f6} - - - \ No newline at end of file diff --git a/Release/tests/dirs.proj b/Release/tests/dirs.proj deleted file mode 100644 index 93af424583..0000000000 --- a/Release/tests/dirs.proj +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/Release/tests/functional/dirs.proj b/Release/tests/functional/dirs.proj deleted file mode 100644 index 7c81a4e0a5..0000000000 --- a/Release/tests/functional/dirs.proj +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/functional/http/client/AuthListener/App.config b/Release/tests/functional/http/client/AuthListener/App.config deleted file mode 100644 index 8e15646352..0000000000 --- a/Release/tests/functional/http/client/AuthListener/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/http/client/AuthListener/Program.cs b/Release/tests/functional/http/client/AuthListener/Program.cs deleted file mode 100644 index eabc9c4844..0000000000 --- a/Release/tests/functional/http/client/AuthListener/Program.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using System; -using System.Collections; -using System.Collections.Specialized; -using System.IO; -using System.Net; -using System.Reflection; -using System.Text; -using System.Threading; - -class Program -{ - /// - /// Checks if the appropriate authentication scheme was used. - /// - /// - /// - /// True if verification was successful, false otherwise. - public static bool VerifyAuthenticationScheme(AuthenticationSchemes listenerAuthScheme, HttpListenerContext requestContext) - { - System.Security.Principal.IIdentity id = null; - if (requestContext.User != null) - { - id = requestContext.User.Identity; - Console.WriteLine("IsAuthenticated:{0}", id.IsAuthenticated); - Console.WriteLine("AuthenticationType:{0}", id.AuthenticationType); - Console.WriteLine("Name:{0}", id.Name); - - if (requestContext.Request.Headers.AllKeys.Contains("UserName")) - { - if (string.Compare(requestContext.Request.Headers["UserName"], id.Name, true) != 0) - { - return false; - } - } - } - - switch (listenerAuthScheme) - { - case AuthenticationSchemes.Anonymous: - if (id != null) - { - return false; - } - break; - case AuthenticationSchemes.Basic: - if (!id.IsAuthenticated || id.AuthenticationType != "Basic") - { - return false; - } - HttpListenerBasicIdentity basicId = (HttpListenerBasicIdentity)id; - if (string.Compare(basicId.Password, requestContext.Request.Headers["Password"], true) != 0) - { - return false; - } - break; - case AuthenticationSchemes.Digest: - if (!id.IsAuthenticated || id.AuthenticationType != "Digest") - { - return false; - } - break; - case AuthenticationSchemes.Ntlm: - if (!id.IsAuthenticated || id.AuthenticationType != "NTLM") - { - return false; - } - break; - case AuthenticationSchemes.Negotiate: - if (!id.IsAuthenticated || id.AuthenticationType != "NTLM") - { - return false; - } - break; - case AuthenticationSchemes.IntegratedWindowsAuthentication: - if (!id.IsAuthenticated || id.AuthenticationType != "NTLM") - { - return false; - } - break; - default: - return false; - } - return true; - } - - static void Main(string []args) - { - if(args.Length != 2) - { - Console.WriteLine("Error: please specify URI to listen on and Authentication type to use:\nAuthListener.exe ServerURI AuthenticationScheme"); - return; - } - string serverUri = args[0]; - AuthenticationSchemes authScheme; - switch(args[1].ToLower()) - { - case "none": - authScheme = AuthenticationSchemes.None; - break; - case "anonymous": - authScheme = AuthenticationSchemes.Anonymous; - break; - case "basic": - authScheme = AuthenticationSchemes.Basic; - break; - case "digest": - authScheme = AuthenticationSchemes.Digest; - break; - case "ntlm": - authScheme = AuthenticationSchemes.Ntlm; - break; - case "negotiate": - authScheme = AuthenticationSchemes.Negotiate; - break; - case "integrated": - authScheme = AuthenticationSchemes.IntegratedWindowsAuthentication; - break; - default: - Console.WriteLine("Error: unrecognized AuthenticationScheme:{0}", args[1]); - return; - } - - HttpListener listener = new HttpListener(); - listener.Prefixes.Add(serverUri); - listener.AuthenticationSchemes = authScheme; - - listener.Start(); - Console.WriteLine("Listening..."); - - HttpListenerContext context = listener.GetContext(); - Console.WriteLine("Received request..."); - StreamWriter writer = new StreamWriter(context.Response.OutputStream); - - // Verify correct authentication scheme was used. - if (!VerifyAuthenticationScheme(listener.AuthenticationSchemes, context)) - { - context.Response.StatusCode = (int)HttpStatusCode.ExpectationFailed; - writer.Write("Error authentication validation failed"); - } - - context.Response.Close(); - } -} \ No newline at end of file diff --git a/Release/tests/functional/http/client/AuthListener/Properties/AssemblyInfo.cs b/Release/tests/functional/http/client/AuthListener/Properties/AssemblyInfo.cs deleted file mode 100644 index c6467dfbe7..0000000000 --- a/Release/tests/functional/http/client/AuthListener/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("AuthListner")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("AuthListner")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2012")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("91128a88-2401-47d2-aef5-c0d72dc55426")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Release/tests/functional/http/client/AuthListener/dirs.proj b/Release/tests/functional/http/client/AuthListener/dirs.proj deleted file mode 100644 index 277f6ee4ec..0000000000 --- a/Release/tests/functional/http/client/AuthListener/dirs.proj +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/Release/tests/functional/http/client/AuthListener/vs12/AuthListener120.csproj b/Release/tests/functional/http/client/AuthListener/vs12/AuthListener120.csproj deleted file mode 100644 index e34311d956..0000000000 --- a/Release/tests/functional/http/client/AuthListener/vs12/AuthListener120.csproj +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - Debug - AnyCPU - {3052AD81-465E-4A2E-B278-DF5FC4BB604C} - Exe - Properties - AuthListener - AuthListener120 - v4.5 - 512 - - - AnyCPU - true - full - false - - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/http/client/dirs.proj b/Release/tests/functional/http/client/dirs.proj deleted file mode 100644 index 56056487eb..0000000000 --- a/Release/tests/functional/http/client/dirs.proj +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/functional/http/client/vs12.winrt/HttpClient120_test.winrt.vcxproj b/Release/tests/functional/http/client/vs12.winrt/HttpClient120_test.winrt.vcxproj deleted file mode 100644 index ccbcd17b16..0000000000 --- a/Release/tests/functional/http/client/vs12.winrt/HttpClient120_test.winrt.vcxproj +++ /dev/null @@ -1,257 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {e66e4531-ac9c-459b-a4ca-87592eb0eeb8} - HttpTests - SAK - SAK - SAK - SAK - en-US - 12.0 - true - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\..\utilities\include;%(AdditionalIncludeDirectories) - - - - - - Use - Disabled - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;%(AdditionalUsingDirectories) - true - false - -Zm350 /bigobj%(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;%(AdditionalUsingDirectories) - true - false - -Zm350 %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;%(AdditionalUsingDirectories) - true - false - -Zm350 /bigobj%(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;%(AdditionalUsingDirectories) - true - false - -Zm350 /bigobj%(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;%(AdditionalUsingDirectories) - true - false - -Zm350 /bigobj%(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;%(AdditionalUsingDirectories) - true - false - -Zm350 /bigobj%(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - {ea2d69a1-55c8-4c15-805e-de7e85872484} - - - {06F4E6FA-152F-4AA7-B8D0-F3EBC5F11F81} - - - {B341AA9C-F38B-4D59-B6B7-8F22491090B7} - - - {198ED804-2655-4D92-8104-C220E3EA9452} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - - - diff --git a/Release/tests/functional/http/client/vs12.winrt/HttpClient120_test.winrt.vcxproj.filters b/Release/tests/functional/http/client/vs12.winrt/HttpClient120_test.winrt.vcxproj.filters deleted file mode 100644 index a8536ce996..0000000000 --- a/Release/tests/functional/http/client/vs12.winrt/HttpClient120_test.winrt.vcxproj.filters +++ /dev/null @@ -1,87 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - - - {fadb7f38-3d0c-4a31-af39-6364be0d9793} - - - {ee68ca67-bbcf-4196-89c7-fbf59083ac16} - - - \ No newline at end of file diff --git a/Release/tests/functional/http/client/vs12/HttpClient120_test.vcxproj b/Release/tests/functional/http/client/vs12/HttpClient120_test.vcxproj deleted file mode 100644 index f0294802c5..0000000000 --- a/Release/tests/functional/http/client/vs12/HttpClient120_test.vcxproj +++ /dev/null @@ -1,234 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {dc215f97-c43c-47f5-9784-711908a24ae3} - HttpTests - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\..\utilities\include;%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - -Zm350 /bigobj%(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;httpapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - -Zm350 /bigobj%(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;httpapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - -Zm350 /bigobj%(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;httpapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - -Zm350 /bigobj%(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;httpapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - -Zm350 /bigobj%(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;httpapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - -Zm350 /bigobj%(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;httpapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - {6837625b-c0db-4fd0-aee2-19699031b76e} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - diff --git a/Release/tests/functional/http/client/vs12/HttpClient120_test.vcxproj.filters b/Release/tests/functional/http/client/vs12/HttpClient120_test.vcxproj.filters deleted file mode 100644 index 6a577a5662..0000000000 --- a/Release/tests/functional/http/client/vs12/HttpClient120_test.vcxproj.filters +++ /dev/null @@ -1,88 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - Source Files - - - - - Header Files - - - Header Files - - - - - {fadb7f38-3d0c-4a31-af39-6364be0d9793} - - - {ee68ca67-bbcf-4196-89c7-fbf59083ac16} - - - \ No newline at end of file diff --git a/Release/tests/functional/http/dirs.proj b/Release/tests/functional/http/dirs.proj deleted file mode 100644 index bce0f05b62..0000000000 --- a/Release/tests/functional/http/dirs.proj +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/Release/tests/functional/http/listener/dirs.proj b/Release/tests/functional/http/listener/dirs.proj deleted file mode 100644 index 160e1126af..0000000000 --- a/Release/tests/functional/http/listener/dirs.proj +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/Release/tests/functional/http/listener/vs12/HttpListener120_test.vcxproj b/Release/tests/functional/http/listener/vs12/HttpListener120_test.vcxproj deleted file mode 100644 index 166fc078ec..0000000000 --- a/Release/tests/functional/http/listener/vs12/HttpListener120_test.vcxproj +++ /dev/null @@ -1,236 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {2853ec0b-1b8e-4d9d-8436-4ef6dded5378} - HttpTests - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - - - - - - - - - - - - - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(TestRoot)\functional\http\utilities\include;%(AdditionalIncludeDirectories) - -Zm140 /bigobj%(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(TestRoot)\functional\http\utilities\include;%(AdditionalIncludeDirectories) - -Zm140 /bigobj%(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(TestRoot)\functional\http\utilities\include;%(AdditionalIncludeDirectories) - -Zm140 /bigobj%(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(TestRoot)\functional\http\utilities\include;%(AdditionalIncludeDirectories) - -Zm140 /bigobj%(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(TestRoot)\functional\http\utilities\include;%(AdditionalIncludeDirectories) - -Zm140 /bigobj%(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(TestRoot)\functional\http\utilities\include;%(AdditionalIncludeDirectories) - -Zm140 /bigobj%(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {6837625b-c0db-4fd0-aee2-19699031b76e} - - - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - diff --git a/Release/tests/functional/http/listener/vs12/HttpListener120_test.vcxproj.filters b/Release/tests/functional/http/listener/vs12/HttpListener120_test.vcxproj.filters deleted file mode 100644 index 8275b21007..0000000000 --- a/Release/tests/functional/http/listener/vs12/HttpListener120_test.vcxproj.filters +++ /dev/null @@ -1,66 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - - - {3de7d3df-7d70-4ea1-a460-bc378ed266c2} - - - {4ac74123-f940-4347-9a8e-d9e35ba7c7ac} - - - \ No newline at end of file diff --git a/Release/tests/functional/http/utilities/dirs.proj b/Release/tests/functional/http/utilities/dirs.proj deleted file mode 100644 index c71ce6f396..0000000000 --- a/Release/tests/functional/http/utilities/dirs.proj +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/functional/http/utilities/vs12.winrt/HttpTestUtilities120.winrt.vcxproj b/Release/tests/functional/http/utilities/vs12.winrt/HttpTestUtilities120.winrt.vcxproj deleted file mode 100644 index f871c60361..0000000000 --- a/Release/tests/functional/http/utilities/vs12.winrt/HttpTestUtilities120.winrt.vcxproj +++ /dev/null @@ -1,246 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {06F4E6FA-152F-4AA7-B8D0-F3EBC5F11F81} - SAK - SAK - SAK - SAK - Win32Proj - en-US - 12.0 - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\include - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - -Zm200 %(AdditionalOptions) - true - false - - - Windows - true - $(VCINSTALLDIR)\lib\store;$(OutDir);%(AdditionalLibraryDirectories); - msvcrtd.lib;msvcprtd.lib;vccorlibd.lib;RuntimeObject.lib;Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - true - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\include - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - -Zm200 %(AdditionalOptions) - true - false - - - Windows - true - $(VCINSTALLDIR)\lib\store\amd64;$(OutDir);%(AdditionalLibraryDirectories); - msvcrtd.lib;msvcprtd.lib;vccorlibd.lib;RuntimeObject.lib;Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - true - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\include - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - -Zm200 %(AdditionalOptions) - true - false - - - Windows - true - $(VCINSTALLDIR)\lib\store\arm;$(OutDir);%(AdditionalLibraryDirectories); - uuid.lib;ole32.lib;msvcrtd.lib;msvcprtd.lib;vccorlibd.lib;RuntimeObject.lib;Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - true - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\include - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - -Zm200 %(AdditionalOptions) - true - false - - - Windows - true - true - true - $(VCINSTALLDIR)\lib\store\arm;$(OutDir);%(AdditionalLibraryDirectories); - uuid.lib;ole32.lib;msvcrt.lib;msvcprt.lib;vccorlib.lib;RuntimeObject.lib;Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - true - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\include - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - -Zm200 %(AdditionalOptions) - true - false - - - Windows - true - true - true - $(VCINSTALLDIR)\lib\store;$(OutDir);%(AdditionalLibraryDirectories); - msvcrt.lib;msvcprt.lib;vccorlib.lib;RuntimeObject.lib;Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - true - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\include - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - -Zm200 %(AdditionalOptions) - true - false - - - Windows - true - true - true - $(VCINSTALLDIR)\lib\store\amd64;$(OutDir);%(AdditionalLibraryDirectories); - msvcrt.lib;msvcprt.lib;vccorlib.lib;RuntimeObject.lib;Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - true - - - - - {ea2d69a1-55c8-4c15-805e-de7e85872484} - - - {B341AA9C-F38B-4D59-B6B7-8F22491090B7} - - - {198ED804-2655-4D92-8104-C220E3EA9452} - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/http/utilities/vs12.winrt/HttpTestUtilities120.winrt.vcxproj.filters b/Release/tests/functional/http/utilities/vs12.winrt/HttpTestUtilities120.winrt.vcxproj.filters deleted file mode 100644 index c965e9cb22..0000000000 --- a/Release/tests/functional/http/utilities/vs12.winrt/HttpTestUtilities120.winrt.vcxproj.filters +++ /dev/null @@ -1,51 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - {96f6b99e-76ae-4ace-801c-39bb8d308125} - - - {d4ba757b-dfdc-4d61-a9bd-19e957c5a09c} - - - \ No newline at end of file diff --git a/Release/tests/functional/http/utilities/vs12/HttpTestUtilities120.vcxproj b/Release/tests/functional/http/utilities/vs12/HttpTestUtilities120.vcxproj deleted file mode 100644 index ff4a1656e9..0000000000 --- a/Release/tests/functional/http/utilities/vs12/HttpTestUtilities120.vcxproj +++ /dev/null @@ -1,218 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {6837625b-c0db-4fd0-aee2-19699031b76e} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\include;%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - -Zm200 %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - -Zm140 %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - -Zm200 %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - -Zm200 %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - -Zm140 %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - -Zm200 %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - - - - - diff --git a/Release/tests/functional/http/utilities/vs12/HttpTestUtilities120.vcxproj.filters b/Release/tests/functional/http/utilities/vs12/HttpTestUtilities120.vcxproj.filters deleted file mode 100644 index 1e583ce8ed..0000000000 --- a/Release/tests/functional/http/utilities/vs12/HttpTestUtilities120.vcxproj.filters +++ /dev/null @@ -1,51 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - {d0052d1d-10e0-42da-9df6-72be473a8ebe} - - - {a4317631-da2e-4508-982f-e689f8d4a039} - - - \ No newline at end of file diff --git a/Release/tests/functional/json/dirs.proj b/Release/tests/functional/json/dirs.proj deleted file mode 100644 index 14b704700e..0000000000 --- a/Release/tests/functional/json/dirs.proj +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/functional/json/vs12.winrt/JSON120_test.winrt.vcxproj b/Release/tests/functional/json/vs12.winrt/JSON120_test.winrt.vcxproj deleted file mode 100644 index 151a7e5be7..0000000000 --- a/Release/tests/functional/json/vs12.winrt/JSON120_test.winrt.vcxproj +++ /dev/null @@ -1,234 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {D398DF71-8642-4BC4-940F-9AE2B0AE1CE4} - SAK - SAK - SAK - SAK - Win32Proj - en-US - 12.0 - $(VCTargetsPath12) - true - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - Use - Disabled - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Console - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Console - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - {ea2d69a1-55c8-4c15-805e-de7e85872484} - - - {B341AA9C-F38B-4D59-B6B7-8F22491090B7} - - - {198ED804-2655-4D92-8104-C220E3EA9452} - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/json/vs12.winrt/JSON120_test.winrt.vcxproj.filters b/Release/tests/functional/json/vs12.winrt/JSON120_test.winrt.vcxproj.filters deleted file mode 100644 index ae62883eba..0000000000 --- a/Release/tests/functional/json/vs12.winrt/JSON120_test.winrt.vcxproj.filters +++ /dev/null @@ -1,42 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - {db714d7a-c017-4d4f-99ab-f1f195ba360c} - - - {3ea4dfd5-d8b3-4370-adda-ea04dcaf401b} - - - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/functional/json/vs12.xp/JSON120_test.xp.vcxproj b/Release/tests/functional/json/vs12.xp/JSON120_test.xp.vcxproj deleted file mode 100644 index 2681aa86e2..0000000000 --- a/Release/tests/functional/json/vs12.xp/JSON120_test.xp.vcxproj +++ /dev/null @@ -1,151 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {ABA69F91-45D4-41D8-991A-10A6319E42C3} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - - - Console - true - $(OutDir)%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - - - Console - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {75885703-7f3d-4086-8e60-c60b9b126f7e} - - - {5AD81270-B089-4E1B-8741-6486F39DE273} - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/json/vs12/JSON120_test.vcxproj b/Release/tests/functional/json/vs12/JSON120_test.vcxproj deleted file mode 100644 index 2290a41c53..0000000000 --- a/Release/tests/functional/json/vs12/JSON120_test.vcxproj +++ /dev/null @@ -1,207 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {6f026328-4d10-4ef1-bd6c-8fd3cbe0f530} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - - - Console - true - $(OutDir)%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - - - Console - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} - - - - - - diff --git a/Release/tests/functional/json/vs12/JSON120_test.vcxproj.filters b/Release/tests/functional/json/vs12/JSON120_test.vcxproj.filters deleted file mode 100644 index 8ee98cfa77..0000000000 --- a/Release/tests/functional/json/vs12/JSON120_test.vcxproj.filters +++ /dev/null @@ -1,44 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/functional/misc/atl_headers/dirs.proj b/Release/tests/functional/misc/atl_headers/dirs.proj deleted file mode 100644 index 93cc367da8..0000000000 --- a/Release/tests/functional/misc/atl_headers/dirs.proj +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/misc/atl_headers/vs12/header_test120.vcxproj b/Release/tests/functional/misc/atl_headers/vs12/header_test120.vcxproj deleted file mode 100644 index b7efae465f..0000000000 --- a/Release/tests/functional/misc/atl_headers/vs12/header_test120.vcxproj +++ /dev/null @@ -1,173 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {32DB3115-2918-477F-B00A-DAC6277EEFAB} - Win32Proj - header_test100 - SAK - SAK - SAK - SAK - atl_header120 - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - Dynamic - Dynamic - v120 - - - DynamicLibrary - true - Unicode - Dynamic - Dynamic - v120 - - - DynamicLibrary - false - true - Unicode - Dynamic - v120 - - - DynamicLibrary - false - true - Unicode - Dynamic - v120 - - - - - - - - - - - - - - - - - - - - - false - - - false - - - - NotUsing - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HEADER_TEST_EXPORTS;%(PreprocessorDefinitions);_AFXDLL - $(CommonTestIncludeDir);$(CasablancaIncludeDir);%(AdditionalIncludeDirectories) - MultiThreadedDebugDLL - - - Windows - true - - - - - NotUsing - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HEADER_TEST_EXPORTS;%(PreprocessorDefinitions);_AFXDLL - $(CommonTestIncludeDir);$(CasablancaIncludeDir);%(AdditionalIncludeDirectories) - MultiThreadedDebugDLL - - - Windows - true - - - - - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HEADER_TEST_EXPORTS;%(PreprocessorDefinitions);_AFXDLL - $(CommonTestIncludeDir);$(CasablancaIncludeDir);%(AdditionalIncludeDirectories) - MultiThreadedDLL - - - Windows - true - true - true - - - - - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HEADER_TEST_EXPORTS;%(PreprocessorDefinitions);_AFXDLL - $(CommonTestIncludeDir);$(CasablancaIncludeDir);%(AdditionalIncludeDirectories) - MultiThreadedDLL - - - Windows - true - true - true - - - - - - - - - - - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/misc/atl_headers/vs12/header_test120.vcxproj.filters b/Release/tests/functional/misc/atl_headers/vs12/header_test120.vcxproj.filters deleted file mode 100644 index 1adba0e43f..0000000000 --- a/Release/tests/functional/misc/atl_headers/vs12/header_test120.vcxproj.filters +++ /dev/null @@ -1,32 +0,0 @@ - - - - - Source FIles - - - Source FIles - - - - - {e9450d87-ef77-4303-b158-baa118a801f2} - - - {aaa56f3f-2db2-4047-a0b4-3b3ba827fef9} - - - {b5ccd6e9-b76b-4fd9-8492-c978dd95f5a3} - - - - - Header Files - - - - - Resource Files - - - \ No newline at end of file diff --git a/Release/tests/functional/misc/dirs.proj b/Release/tests/functional/misc/dirs.proj deleted file mode 100644 index 43af01e15e..0000000000 --- a/Release/tests/functional/misc/dirs.proj +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - diff --git a/Release/tests/functional/misc/version/dirs.proj b/Release/tests/functional/misc/version/dirs.proj deleted file mode 100644 index f3f76d4aac..0000000000 --- a/Release/tests/functional/misc/version/dirs.proj +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/pplx/dirs.proj b/Release/tests/functional/pplx/dirs.proj deleted file mode 100644 index 1ce745ee07..0000000000 --- a/Release/tests/functional/pplx/dirs.proj +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/Release/tests/functional/pplx/pplx_test/dirs.proj b/Release/tests/functional/pplx/pplx_test/dirs.proj deleted file mode 100644 index 559175d100..0000000000 --- a/Release/tests/functional/pplx/pplx_test/dirs.proj +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/functional/pplx/pplx_test/vs12.winrt/pplx120_test.winrt.vcxproj b/Release/tests/functional/pplx/pplx_test/vs12.winrt/pplx120_test.winrt.vcxproj deleted file mode 100644 index 4c8d4314a3..0000000000 --- a/Release/tests/functional/pplx/pplx_test/vs12.winrt/pplx120_test.winrt.vcxproj +++ /dev/null @@ -1,228 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {23A43AC2-1E04-4589-B0A9-0295962755DC} - Win32Proj - HttpTests - SAK - SAK - SAK - SAK - en-US - 12.0 - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - true - false - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - true - false - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - true - false - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - true - false - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - true - false - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - true - false - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {ea2d69a1-55c8-4c15-805e-de7e85872484} - - - {B341AA9C-F38B-4D59-B6B7-8F22491090B7} - - - {198ED804-2655-4D92-8104-C220E3EA9452} - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/pplx/pplx_test/vs12.xp/pplx120_test.xp.vcxproj b/Release/tests/functional/pplx/pplx_test/vs12.xp/pplx120_test.xp.vcxproj deleted file mode 100644 index 04ec221801..0000000000 --- a/Release/tests/functional/pplx/pplx_test/vs12.xp/pplx120_test.xp.vcxproj +++ /dev/null @@ -1,158 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {EB4A3750-CA93-4968-89D7-3ED467DB2C59} - Win32Proj - HttpTests - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Level4 - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Level4 - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Level4 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Level4 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - Create - Create - Create - Create - - - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {5ad81270-b089-4e1b-8741-6486f39de273} - - - {75885703-7F3D-4086-8E60-C60B9B126F7E} - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/pplx/pplx_test/vs12/pplx120_test.vcxproj b/Release/tests/functional/pplx/pplx_test/vs12/pplx120_test.vcxproj deleted file mode 100644 index 2d391753e2..0000000000 --- a/Release/tests/functional/pplx/pplx_test/vs12/pplx120_test.vcxproj +++ /dev/null @@ -1,216 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {5115840e-a5a8-4044-b595-cda05c2d65d0} - Win32Proj - HttpTests - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - - Level3 - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Level3 - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Level3 - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/streams/dirs.proj b/Release/tests/functional/streams/dirs.proj deleted file mode 100644 index 1740e6d983..0000000000 --- a/Release/tests/functional/streams/dirs.proj +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/functional/streams/vs12.winrt/streams120_test.winrt.vcxproj b/Release/tests/functional/streams/vs12.winrt/streams120_test.winrt.vcxproj deleted file mode 100644 index 1eac7a67bd..0000000000 --- a/Release/tests/functional/streams/vs12.winrt/streams120_test.winrt.vcxproj +++ /dev/null @@ -1,246 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {337E0660-2300-4DC6-883E-283D5A7281B5} - Win32Proj - SAK - SAK - SAK - SAK - en-US - 12.0 - true - $(VCTargetsPath12) - e13f21ed - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - Unicode - v120 - - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - /bigobj %(AdditionalOptions) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - -Zm160 %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - /bigobj %(AdditionalOptions) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - -Zm160 %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - /bigobj %(AdditionalOptions) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - -Zm160 %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - /bigobj %(AdditionalOptions) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - -Zm160 %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - /bigobj %(AdditionalOptions) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - -Zm160 %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - /bigobj %(AdditionalOptions) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - -Zm160 %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - {ea2d69a1-55c8-4c15-805e-de7e85872484} - - - {B341AA9C-F38B-4D59-B6B7-8F22491090B7} - - - {198ED804-2655-4D92-8104-C220E3EA9452} - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/streams/vs12.winrt/streams120_test.winrt.vcxproj.filters b/Release/tests/functional/streams/vs12.winrt/streams120_test.winrt.vcxproj.filters deleted file mode 100644 index 86b36e3575..0000000000 --- a/Release/tests/functional/streams/vs12.winrt/streams120_test.winrt.vcxproj.filters +++ /dev/null @@ -1,45 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - {274676f3-573c-4a10-adbb-0421159c8a2a} - - - {dd303bf1-0c87-4079-a035-c16d23cf129d} - - - - - Header Files - - - Header Files - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/streams/vs12.xp/streams120_test.xp.vcxproj b/Release/tests/functional/streams/vs12.xp/streams120_test.xp.vcxproj deleted file mode 100644 index 3ced480633..0000000000 --- a/Release/tests/functional/streams/vs12.xp/streams120_test.xp.vcxproj +++ /dev/null @@ -1,163 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {F279F1ED-8AFF-478D-9A20-DDCAD8CBA336} - Win32Proj - HttpTests - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - 2276c549 - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {75885703-7f3d-4086-8e60-c60b9b126f7e} - - - {5ad81270-b089-4e1b-8741-6486f39de273} - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/streams/vs12/streams120_test.vcxproj b/Release/tests/functional/streams/vs12/streams120_test.vcxproj deleted file mode 100644 index 04c97f0915..0000000000 --- a/Release/tests/functional/streams/vs12/streams120_test.vcxproj +++ /dev/null @@ -1,216 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {181ccb80-9ae8-4ed7-8b7d-4c0cbc80eedd} - Win32Proj - HttpTests - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - 84fd5b75 - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - ARM;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - ARM;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} - - - - - - - - - - diff --git a/Release/tests/functional/streams/vs12/streams120_test.vcxproj.filters b/Release/tests/functional/streams/vs12/streams120_test.vcxproj.filters deleted file mode 100644 index fec2efca0f..0000000000 --- a/Release/tests/functional/streams/vs12/streams120_test.vcxproj.filters +++ /dev/null @@ -1,43 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - - {1de3a9ce-57af-48bd-8125-3af4f406be26} - - - {3c2936bc-8d1e-4a33-96c9-5cfb3d83b30d} - - - - - Header Files - - - Header Files - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/uri/dirs.proj b/Release/tests/functional/uri/dirs.proj deleted file mode 100644 index fcaf28aa55..0000000000 --- a/Release/tests/functional/uri/dirs.proj +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/functional/uri/vs12.winrt/URI120_test.winrt.vcxproj.filters b/Release/tests/functional/uri/vs12.winrt/URI120_test.winrt.vcxproj.filters deleted file mode 100644 index fd4f136ea8..0000000000 --- a/Release/tests/functional/uri/vs12.winrt/URI120_test.winrt.vcxproj.filters +++ /dev/null @@ -1,57 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - {e30fa8ae-3cb4-4a63-870b-a7e85088a9ad} - - - {e7f8af98-2e23-4c57-93e1-2936a3f0ac84} - - - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/functional/uri/vs12.winrt/Uri120_test.winrt.vcxproj b/Release/tests/functional/uri/vs12.winrt/Uri120_test.winrt.vcxproj deleted file mode 100644 index 52abbff812..0000000000 --- a/Release/tests/functional/uri/vs12.winrt/Uri120_test.winrt.vcxproj +++ /dev/null @@ -1,234 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {9169C20C-B98A-46C6-A138-A107C458E8DD} - SAK - SAK - SAK - SAK - Win32Proj - en-US - 12.0 - true - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - Use - Disabled - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {ea2d69a1-55c8-4c15-805e-de7e85872484} - - - {B341AA9C-F38B-4D59-B6B7-8F22491090B7} - - - {198ED804-2655-4D92-8104-C220E3EA9452} - - - - - - - - - - - - - - diff --git a/Release/tests/functional/uri/vs12.xp/Uri120_test.xp.vcxproj b/Release/tests/functional/uri/vs12.xp/Uri120_test.xp.vcxproj deleted file mode 100644 index 201dae39c4..0000000000 --- a/Release/tests/functional/uri/vs12.xp/Uri120_test.xp.vcxproj +++ /dev/null @@ -1,155 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {66B6D1E2-A91C-4DA3-8568-B7457FA7ED6D} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {75885703-7f3d-4086-8e60-c60b9b126f7e} - - - {5ad81270-b089-4e1b-8741-6486f39de273} - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/uri/vs12/Uri120_test.vcxproj b/Release/tests/functional/uri/vs12/Uri120_test.vcxproj deleted file mode 100644 index bc0e8c5861..0000000000 --- a/Release/tests/functional/uri/vs12/Uri120_test.vcxproj +++ /dev/null @@ -1,208 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {3d9c3f25-1736-4d39-a31f-6b2de34e20cf} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} - - - - - - diff --git a/Release/tests/functional/uri/vs12/Uri120_test.vcxproj.filters b/Release/tests/functional/uri/vs12/Uri120_test.vcxproj.filters deleted file mode 100644 index 8c9f65a853..0000000000 --- a/Release/tests/functional/uri/vs12/Uri120_test.vcxproj.filters +++ /dev/null @@ -1,59 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/functional/utils/dirs.proj b/Release/tests/functional/utils/dirs.proj deleted file mode 100644 index f01337a94f..0000000000 --- a/Release/tests/functional/utils/dirs.proj +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/functional/utils/vs12.winrt/Utils120_test.winrt.vcxproj b/Release/tests/functional/utils/vs12.winrt/Utils120_test.winrt.vcxproj deleted file mode 100644 index 30335ca23c..0000000000 --- a/Release/tests/functional/utils/vs12.winrt/Utils120_test.winrt.vcxproj +++ /dev/null @@ -1,229 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {4fddc511-5cfd-48a0-b373-43b13a43fb45} - SAK - SAK - SAK - SAK - Win32Proj - en-US - 12.0 - true - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - Use - Disabled - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {ea2d69a1-55c8-4c15-805e-de7e85872484} - - - {B341AA9C-F38B-4D59-B6B7-8F22491090B7} - - - {198ED804-2655-4D92-8104-C220E3EA9452} - - - - - - - - - - - - - diff --git a/Release/tests/functional/utils/vs12.winrt/Utils120_test.winrt.vcxproj.filters b/Release/tests/functional/utils/vs12.winrt/Utils120_test.winrt.vcxproj.filters deleted file mode 100644 index a2199f62fb..0000000000 --- a/Release/tests/functional/utils/vs12.winrt/Utils120_test.winrt.vcxproj.filters +++ /dev/null @@ -1,36 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - {e30fa8ae-3cb4-4a63-870b-a7e85088a9ad} - - - {e7f8af98-2e23-4c57-93e1-2936a3f0ac84} - - - Source Files - - - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/functional/utils/vs12.xp/Utils120_test.xp.vcxproj b/Release/tests/functional/utils/vs12.xp/Utils120_test.xp.vcxproj deleted file mode 100644 index 2067371412..0000000000 --- a/Release/tests/functional/utils/vs12.xp/Utils120_test.xp.vcxproj +++ /dev/null @@ -1,151 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {E9E26CDB-4CE3-4B0E-AAF8-D32F57E48856} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {75885703-7f3d-4086-8e60-c60b9b126f7e} - - - {5ad81270-b089-4e1b-8741-6486f39de273} - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/utils/vs12/Utils120_test.vcxproj b/Release/tests/functional/utils/vs12/Utils120_test.vcxproj deleted file mode 100644 index 620d770a0f..0000000000 --- a/Release/tests/functional/utils/vs12/Utils120_test.vcxproj +++ /dev/null @@ -1,202 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {50386698-0180-4ebc-8827-f2c36561f6b4} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - - - diff --git a/Release/tests/functional/utils/vs12/Utils120_test.vcxproj.filters b/Release/tests/functional/utils/vs12/Utils120_test.vcxproj.filters deleted file mode 100644 index dfa7b86991..0000000000 --- a/Release/tests/functional/utils/vs12/Utils120_test.vcxproj.filters +++ /dev/null @@ -1,38 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/functional/websockets/client/dirs.proj b/Release/tests/functional/websockets/client/dirs.proj deleted file mode 100644 index 15d6dbc4dd..0000000000 --- a/Release/tests/functional/websockets/client/dirs.proj +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/functional/websockets/client/vs12.winrt/websocketsclient120_test.winrt.vcxproj b/Release/tests/functional/websockets/client/vs12.winrt/websocketsclient120_test.winrt.vcxproj deleted file mode 100644 index 6ca0b5efeb..0000000000 --- a/Release/tests/functional/websockets/client/vs12.winrt/websocketsclient120_test.winrt.vcxproj +++ /dev/null @@ -1,179 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {8E3772EF-7807-40DA-8932-F37DB0C1CB44} - SAK - SAK - SAK - SAK - en-US - 12.0 - true - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - Use - Disabled - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\..\utilities; - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - -Zm200 %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\..\utilities - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - -Zm200 %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\..\utilities - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - -Zm200 %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WINAPI_FAMILY=WINAPI_PARTITION_APP;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\..\utilities - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - -Zm200 %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - {ea2d69a1-55c8-4c15-805e-de7e85872484} - - - {B341AA9C-F38B-4D59-B6B7-8F22491090B7} - - - {198ED804-2655-4D92-8104-C220E3EA9452} - - - {D422311C-1C3A-4083-A564-6474EA60FFC7} - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/websockets/client/vs12.xp/websocketsclient120_test.xp.vcxproj b/Release/tests/functional/websockets/client/vs12.xp/websocketsclient120_test.xp.vcxproj deleted file mode 100644 index e2bd01c665..0000000000 --- a/Release/tests/functional/websockets/client/vs12.xp/websocketsclient120_test.xp.vcxproj +++ /dev/null @@ -1,123 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - WebsocketTests - SAK - SAK - SAK - SAK - websocketsclient120_test.xp - {BBE711C0-568C-48E5-A9EB-2F3741D0687B} - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - Use - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\..\utilities;%(AdditionalIncludeDirectories) - - - Windows - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Disabled - CPPREST_TARGET_XP;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - - - MaxSpeed - true - true - CPPREST_TARGET_XP;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - true - true - - - - - {75885703-7f3d-4086-8e60-c60b9b126f7e} - - - {3eb86c0d-432c-4ffc-bad4-8df4efc7d0ff} - - - {5AD81270-B089-4E1B-8741-6486F39DE273} - - - {3803246A-F31E-44EC-BCA9-87DF68C5EB8D} - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - diff --git a/Release/tests/functional/websockets/client/vs12/websocketsclient120_test.vcxproj b/Release/tests/functional/websockets/client/vs12/websocketsclient120_test.vcxproj deleted file mode 100644 index 8d02565a3c..0000000000 --- a/Release/tests/functional/websockets/client/vs12/websocketsclient120_test.vcxproj +++ /dev/null @@ -1,129 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {9A23F9D2-4876-423B-9393-A604764601B0} - WebsocketTests - SAK - SAK - SAK - SAK - websocketsclient120_test - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - Use - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\..\utilities;%(AdditionalIncludeDirectories) - - - Windows - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - StdCall - StdCall - - - - - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - StdCall - StdCall - - - true - true - - - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - {3eb86c0d-432c-4ffc-bad4-8df4efc7d0ff} - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {14f7b7a0-a057-4e15-8ec4-12baf00b0f64} - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/websockets/dirs.proj b/Release/tests/functional/websockets/dirs.proj deleted file mode 100644 index 2c3829d5b2..0000000000 --- a/Release/tests/functional/websockets/dirs.proj +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/Release/tests/functional/websockets/utilities/dirs.proj b/Release/tests/functional/websockets/utilities/dirs.proj deleted file mode 100644 index e063f42b24..0000000000 --- a/Release/tests/functional/websockets/utilities/dirs.proj +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/functional/websockets/utilities/vs12.winrt/websockets_test_utilities120.winrt.vcxproj b/Release/tests/functional/websockets/utilities/vs12.winrt/websockets_test_utilities120.winrt.vcxproj deleted file mode 100644 index 9de41c333e..0000000000 --- a/Release/tests/functional/websockets/utilities/vs12.winrt/websockets_test_utilities120.winrt.vcxproj +++ /dev/null @@ -1,178 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {D422311C-1C3A-4083-A564-6474EA60FFC7} - SAK - SAK - SAK - SAK - Win32Proj - en-US - 12.0 - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;WEBSOCKETTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(WebsocketppIncludeDir);..\include - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - -Zm200 %(AdditionalOptions) - true - false - - - Windows - true - $(VCINSTALLDIR)\lib\store;$(OutDir);%(AdditionalLibraryDirectories); - msvcrtd.lib;msvcprtd.lib;vccorlibd.lib;RuntimeObject.lib;Ws2_32.lib;Mswsock.lib;libboost_system-vc120-mt-gd-1_58.lib;%(AdditionalDependencies) - true - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;WEBSOCKETTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(WebsocketppIncludeDir);..\include - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - -Zm200 %(AdditionalOptions) - true - false - - - Windows - true - $(VCINSTALLDIR)\lib\store\amd64;$(OutDir);%(AdditionalLibraryDirectories); - msvcrtd.lib;msvcprtd.lib;vccorlibd.lib;RuntimeObject.lib;Ws2_32.lib;Mswsock.lib;libboost_system-vc120-mt-gd-1_58.lib;%(AdditionalDependencies) - true - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;WEBSOCKETTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(WebsocketppIncludeDir);..\include - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - -Zm200 %(AdditionalOptions) - true - false - - - Windows - true - true - true - $(VCINSTALLDIR)\lib\store;$(OutDir);%(AdditionalLibraryDirectories); - msvcrt.lib;msvcprt.lib;vccorlib.lib;RuntimeObject.lib;Ws2_32.lib;Mswsock.lib;libboost_system-vc120-mt-1_58.lib;%(AdditionalDependencies) - true - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;WEBSOCKETTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(WebsocketppIncludeDir);..\include - $(WindowsSDKDir)\References\CommonConfiguration\Neutral;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - -Zm200 %(AdditionalOptions) - true - false - - - Windows - true - true - true - $(VCINSTALLDIR)\lib\store\amd64;$(OutDir);%(AdditionalLibraryDirectories); - msvcrt.lib;msvcprt.lib;vccorlib.lib;RuntimeObject.lib;Ws2_32.lib;Mswsock.lib;libboost_system-vc120-mt-1_58.lib;%(AdditionalDependencies) - true - - - - - {ea2d69a1-55c8-4c15-805e-de7e85872484} - - - {B341AA9C-F38B-4D59-B6B7-8F22491090B7} - - - {198ED804-2655-4D92-8104-C220E3EA9452} - - - - - - Create - Create - Create - Create - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/websockets/utilities/vs12.xp/websockets_test_utilities120.xp.vcxproj b/Release/tests/functional/websockets/utilities/vs12.xp/websockets_test_utilities120.xp.vcxproj deleted file mode 100644 index 52a10dfef0..0000000000 --- a/Release/tests/functional/websockets/utilities/vs12.xp/websockets_test_utilities120.xp.vcxproj +++ /dev/null @@ -1,132 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - SAK - SAK - SAK - SAK - Win32Proj - en-US - 11.0 - tests::common::websockets_test_utilities - websockets_test_utilities120.xp - {3803246A-F31E-44EC-BCA9-87DF68C5EB8D} - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - Use - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(WebsocketppIncludeDir);$(TestRoot)\Common\UnitTestpp\src\;%(AdditionalIncludeDirectories) - - - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - - - Windows - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;WEBSOCKETTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - - - - - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;WEBSOCKETTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - - - true - true - - - - - - Create - Create - Create - Create - - - - - - - - - {3eb86c0d-432c-4ffc-bad4-8df4efc7d0ff} - - - {75885703-7f3d-4086-8e60-c60b9b126f7e} - - - {5AD81270-B089-4E1B-8741-6486F39DE273} - - - - - - - - - - - - - diff --git a/Release/tests/functional/websockets/utilities/vs12/packages.config b/Release/tests/functional/websockets/utilities/vs12/packages.config deleted file mode 100644 index b1cabf8f3a..0000000000 --- a/Release/tests/functional/websockets/utilities/vs12/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/websockets/utilities/vs12/websockets_test_utilities120.vcxproj b/Release/tests/functional/websockets/utilities/vs12/websockets_test_utilities120.vcxproj deleted file mode 100644 index c1a2a04c09..0000000000 --- a/Release/tests/functional/websockets/utilities/vs12/websockets_test_utilities120.vcxproj +++ /dev/null @@ -1,157 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {14F7B7A0-A057-4E15-8EC4-12BAF00B0F64} - SAK - SAK - SAK - SAK - Win32Proj - en-US - 11.0 - tests::common::websockets_test_utilities - websockets_test_utilities120 - - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - DynamicLibrary - false - true - Unicode - v120 - - - - - - - Use - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(WebsocketppIncludeDir);$(TestRoot)\Common\UnitTestpp\src\;%(AdditionalIncludeDirectories) - - - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - - - Windows - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - Disabled - _DEBUG;_WINDOWS;_USRDLL;WEBSOCKETTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - - - - - MaxSpeed - true - true - NDEBUG;_WINDOWS;_USRDLL;WEBSOCKETTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - - - true - true - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {3eb86c0d-432c-4ffc-bad4-8df4efc7d0ff} - - - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} - - - - - - - - - - - - - diff --git a/cpprestsdk120.sln b/cpprestsdk120.sln deleted file mode 100644 index 59fc89bf4c..0000000000 --- a/cpprestsdk120.sln +++ /dev/null @@ -1,321 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "android", "Release\src\build\android.vcxitems", "{65951C40-A332-4B54-89C2-7CDAF30D5F66}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "Release\src\build\common.vcxitems", "{594DCB5F-07E3-4084-A2CE-268611FA629F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "other", "Release\src\build\other.vcxitems", "{3D5908F7-7673-4229-BC46-2007A7AF9CAE}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win32", "Release\src\build\win32.vcxitems", "{F40F4804-50F9-4257-8D74-B9CBB19AC4C3}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winrt", "Release\src\build\winrt.vcxitems", "{0A9BA181-7876-4B3D-A5E0-EE673FA51C05}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprestsdk120", "Release\src\build\vs12\casablanca120.vcxproj", "{01A76234-E6E8-4332-9FE2-1E12C34621BE}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprestsdk120.winrt", "Release\src\build\vs12.winrt\casablanca120.winrt.vcxproj", "{9AD285A2-301E-47A0-A299-14AD5D4F2758}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprestsdk120.xp", "Release\src\build\vs12.xp\casablanca120.xp.vcxproj", "{15F3B200-1AED-4B57-AF37-B21CD67914B1}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprestsdk120.wps81", "Release\src\build\vs12.wps81\casablanca120.wps81.vcxproj", "{C5D88D15-F9F5-48E2-9EF2-BE0B645B9C0D}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprestsdk120.wp81", "Release\src\build\vs12.wp81\casablanca120.wp81.vcxproj", "{E5F8A2F0-F713-4673-A42F-2CC4E8FB171B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{E25A1A01-9AB0-41C5-A03B-F6B83F5E66B9}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{B27A3D67-1423-48D8-9F6D-D8FD7E682EC7}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BingRequest", "BingRequest", "{06A71AA7-132E-4A1B-A353-C36B2779331F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BingRequest120", "Release\samples\BingRequest\BingRequest120\BingRequest120.vcxproj", "{2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BingRequest120.xp", "Release\samples\BingRequest\BingRequest120.xp\BingRequest120.xp.vcxproj", "{7009BCBE-D67C-4B54-BEFC-A44E62656CF1}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SearchFile", "SearchFile", "{CA4D2B5D-D78C-4165-B8E6-0126FF584FCB}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SearchFile120", "Release\samples\SearchFile\SearchFile120\SearchFile120.vcxproj", "{F03BEE03-BEFB-4B17-A774-D9C8246530D4}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CasaLens", "CasaLens", "{BBB2B70F-1D96-4597-96B0-75EA9BE3CA2A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CasaLens120", "Release\samples\CasaLens\CasaLens120\CasaLens120.vcxproj", "{FFBFD6C1-B525-4D35-AB64-A2FE9460B147}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BlackJack", "BlackJack", "{843B16ED-DE6A-4541-B700-D65B384D43A0}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{E442BD21-6B65-4D0E-A96C-623F605A9517}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Server", "Server", "{3D3149CF-B1FF-40C0-BD59-1B41FC3522F0}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlackJack_Client120", "Release\samples\BlackJack\BlackJack_Client\BlackJack_Client120\BlackJack_Client120.vcxproj", "{830B6E2F-9224-41D1-B9C7-A51FC78B00C7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlackJack_Server120", "Release\samples\BlackJack\BlackJack_Server\BlackJack_Server120\BlackJack_Server120.vcxproj", "{84350CD1-D406-4A4F-9571-261CA46D77C5}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WindowsLiveAuth", "WindowsLiveAuth", "{052831C4-6B41-4A52-A740-4228EB79CF3B}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsLiveAuth120", "Release\samples\WindowsLiveAuth\WindowsLiveAuth120.vcxproj", "{1C20F771-3131-46E8-805F-AA1FE44165C0}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UIClient", "UIClient", "{11041CA3-4C29-41E4-9C76-36AF06268C19}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlackJack_UIClient120", "Release\samples\BlackJack\BlackJack_UIClient\BlackJack_UIClient120.vcxproj", "{B8D3F85B-DA71-4ACA-87BA-10FED681DC79}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Facebook", "Facebook", "{3E5DF179-3668-49DA-9B6D-38C0632D8F28}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FacebookDemo120", "Release\samples\FacebookDemo\FacebookDemo120.vcxproj", "{43DE4DF3-ACAA-429E-B260-CC6D4FE82658}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprestsdk120.wod", "Release\src\build\vs12.wod\casablanca120.wod.vcxproj", "{BA4F15A0-6F9C-4ED6-A132-D6F7D0E08D6A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprestsdk120.xp.static", "Release\src\build\vs12.xp.static\casablanca120.xp.static.vcxproj", "{CF74448D-FE99-4E3C-AFA6-A50F3145BAF3}" -EndProject -Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - Release\src\build\win32.vcxitems*{cf74448d-fe99-4e3c-afa6-a50f3145baf3}*SharedItemsImports = 4 - Release\src\build\common.vcxitems*{cf74448d-fe99-4e3c-afa6-a50f3145baf3}*SharedItemsImports = 4 - Release\src\build\winrt.vcxitems*{0a9ba181-7876-4b3d-a5e0-ee673fa51c05}*SharedItemsImports = 9 - Release\src\build\android.vcxitems*{65951c40-a332-4b54-89c2-7cdaf30d5f66}*SharedItemsImports = 9 - Release\src\build\win32.vcxitems*{15f3b200-1aed-4b57-af37-b21cd67914b1}*SharedItemsImports = 4 - Release\src\build\common.vcxitems*{15f3b200-1aed-4b57-af37-b21cd67914b1}*SharedItemsImports = 4 - Release\src\build\win32.vcxitems*{01a76234-e6e8-4332-9fe2-1e12c34621be}*SharedItemsImports = 4 - Release\src\build\common.vcxitems*{01a76234-e6e8-4332-9fe2-1e12c34621be}*SharedItemsImports = 4 - Release\src\build\win32.vcxitems*{ba4f15a0-6f9c-4ed6-a132-d6f7d0e08d6a}*SharedItemsImports = 4 - Release\src\build\common.vcxitems*{ba4f15a0-6f9c-4ed6-a132-d6f7d0e08d6a}*SharedItemsImports = 4 - Release\src\build\win32.vcxitems*{f40f4804-50f9-4257-8d74-b9cbb19ac4c3}*SharedItemsImports = 9 - Release\src\build\other.vcxitems*{3d5908f7-7673-4229-bc46-2007a7af9cae}*SharedItemsImports = 9 - Release\src\build\common.vcxitems*{594dcb5f-07e3-4084-a2ce-268611fa629f}*SharedItemsImports = 9 - EndGlobalSection - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|ARM = Debug|ARM - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|ARM = Release|ARM - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {01A76234-E6E8-4332-9FE2-1E12C34621BE}.Debug|ARM.ActiveCfg = Debug|ARM - {01A76234-E6E8-4332-9FE2-1E12C34621BE}.Debug|Win32.ActiveCfg = Debug|Win32 - {01A76234-E6E8-4332-9FE2-1E12C34621BE}.Debug|Win32.Build.0 = Debug|Win32 - {01A76234-E6E8-4332-9FE2-1E12C34621BE}.Debug|x64.ActiveCfg = Debug|x64 - {01A76234-E6E8-4332-9FE2-1E12C34621BE}.Debug|x64.Build.0 = Debug|x64 - {01A76234-E6E8-4332-9FE2-1E12C34621BE}.Release|ARM.ActiveCfg = Release|ARM - {01A76234-E6E8-4332-9FE2-1E12C34621BE}.Release|Win32.ActiveCfg = Release|Win32 - {01A76234-E6E8-4332-9FE2-1E12C34621BE}.Release|Win32.Build.0 = Release|Win32 - {01A76234-E6E8-4332-9FE2-1E12C34621BE}.Release|x64.ActiveCfg = Release|x64 - {01A76234-E6E8-4332-9FE2-1E12C34621BE}.Release|x64.Build.0 = Release|x64 - {9AD285A2-301E-47A0-A299-14AD5D4F2758}.Debug|ARM.ActiveCfg = Debug|ARM - {9AD285A2-301E-47A0-A299-14AD5D4F2758}.Debug|ARM.Build.0 = Debug|ARM - {9AD285A2-301E-47A0-A299-14AD5D4F2758}.Debug|Win32.ActiveCfg = Debug|Win32 - {9AD285A2-301E-47A0-A299-14AD5D4F2758}.Debug|Win32.Build.0 = Debug|Win32 - {9AD285A2-301E-47A0-A299-14AD5D4F2758}.Debug|x64.ActiveCfg = Debug|x64 - {9AD285A2-301E-47A0-A299-14AD5D4F2758}.Debug|x64.Build.0 = Debug|x64 - {9AD285A2-301E-47A0-A299-14AD5D4F2758}.Release|ARM.ActiveCfg = Release|ARM - {9AD285A2-301E-47A0-A299-14AD5D4F2758}.Release|ARM.Build.0 = Release|ARM - {9AD285A2-301E-47A0-A299-14AD5D4F2758}.Release|Win32.ActiveCfg = Release|Win32 - {9AD285A2-301E-47A0-A299-14AD5D4F2758}.Release|Win32.Build.0 = Release|Win32 - {9AD285A2-301E-47A0-A299-14AD5D4F2758}.Release|x64.ActiveCfg = Release|x64 - {9AD285A2-301E-47A0-A299-14AD5D4F2758}.Release|x64.Build.0 = Release|x64 - {15F3B200-1AED-4B57-AF37-B21CD67914B1}.Debug|ARM.ActiveCfg = Debug|ARM - {15F3B200-1AED-4B57-AF37-B21CD67914B1}.Debug|Win32.ActiveCfg = Debug|Win32 - {15F3B200-1AED-4B57-AF37-B21CD67914B1}.Debug|Win32.Build.0 = Debug|Win32 - {15F3B200-1AED-4B57-AF37-B21CD67914B1}.Debug|x64.ActiveCfg = Debug|x64 - {15F3B200-1AED-4B57-AF37-B21CD67914B1}.Debug|x64.Build.0 = Debug|x64 - {15F3B200-1AED-4B57-AF37-B21CD67914B1}.Release|ARM.ActiveCfg = Release|ARM - {15F3B200-1AED-4B57-AF37-B21CD67914B1}.Release|Win32.ActiveCfg = Release|Win32 - {15F3B200-1AED-4B57-AF37-B21CD67914B1}.Release|Win32.Build.0 = Release|Win32 - {15F3B200-1AED-4B57-AF37-B21CD67914B1}.Release|x64.ActiveCfg = Release|x64 - {15F3B200-1AED-4B57-AF37-B21CD67914B1}.Release|x64.Build.0 = Release|x64 - {C5D88D15-F9F5-48E2-9EF2-BE0B645B9C0D}.Debug|ARM.ActiveCfg = Debug|ARM - {C5D88D15-F9F5-48E2-9EF2-BE0B645B9C0D}.Debug|ARM.Build.0 = Debug|ARM - {C5D88D15-F9F5-48E2-9EF2-BE0B645B9C0D}.Debug|Win32.ActiveCfg = Debug|Win32 - {C5D88D15-F9F5-48E2-9EF2-BE0B645B9C0D}.Debug|Win32.Build.0 = Debug|Win32 - {C5D88D15-F9F5-48E2-9EF2-BE0B645B9C0D}.Debug|x64.ActiveCfg = Debug|x64 - {C5D88D15-F9F5-48E2-9EF2-BE0B645B9C0D}.Release|ARM.ActiveCfg = Release|ARM - {C5D88D15-F9F5-48E2-9EF2-BE0B645B9C0D}.Release|ARM.Build.0 = Release|ARM - {C5D88D15-F9F5-48E2-9EF2-BE0B645B9C0D}.Release|Win32.ActiveCfg = Release|Win32 - {C5D88D15-F9F5-48E2-9EF2-BE0B645B9C0D}.Release|Win32.Build.0 = Release|Win32 - {C5D88D15-F9F5-48E2-9EF2-BE0B645B9C0D}.Release|x64.ActiveCfg = Release|x64 - {E5F8A2F0-F713-4673-A42F-2CC4E8FB171B}.Debug|ARM.ActiveCfg = Debug|ARM - {E5F8A2F0-F713-4673-A42F-2CC4E8FB171B}.Debug|ARM.Build.0 = Debug|ARM - {E5F8A2F0-F713-4673-A42F-2CC4E8FB171B}.Debug|Win32.ActiveCfg = Debug|Win32 - {E5F8A2F0-F713-4673-A42F-2CC4E8FB171B}.Debug|Win32.Build.0 = Debug|Win32 - {E5F8A2F0-F713-4673-A42F-2CC4E8FB171B}.Debug|x64.ActiveCfg = Debug|x64 - {E5F8A2F0-F713-4673-A42F-2CC4E8FB171B}.Release|ARM.ActiveCfg = Release|ARM - {E5F8A2F0-F713-4673-A42F-2CC4E8FB171B}.Release|ARM.Build.0 = Release|ARM - {E5F8A2F0-F713-4673-A42F-2CC4E8FB171B}.Release|Win32.ActiveCfg = Release|Win32 - {E5F8A2F0-F713-4673-A42F-2CC4E8FB171B}.Release|Win32.Build.0 = Release|Win32 - {E5F8A2F0-F713-4673-A42F-2CC4E8FB171B}.Release|x64.ActiveCfg = Release|x64 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|ARM.ActiveCfg = Debug|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|Win32.ActiveCfg = Debug|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|Win32.Build.0 = Debug|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|x64.ActiveCfg = Debug|x64 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|x64.Build.0 = Debug|x64 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|ARM.ActiveCfg = Release|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|Win32.ActiveCfg = Release|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|Win32.Build.0 = Release|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x64.ActiveCfg = Release|x64 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x64.Build.0 = Release|x64 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Debug|ARM.ActiveCfg = Debug|Win32 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Debug|Win32.ActiveCfg = Debug|Win32 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Debug|Win32.Build.0 = Debug|Win32 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Debug|x64.ActiveCfg = Debug|x64 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Debug|x64.Build.0 = Debug|x64 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Release|ARM.ActiveCfg = Release|Win32 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Release|Win32.ActiveCfg = Release|Win32 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Release|Win32.Build.0 = Release|Win32 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Release|x64.ActiveCfg = Release|x64 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Release|x64.Build.0 = Release|x64 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|ARM.ActiveCfg = Debug|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|Win32.ActiveCfg = Debug|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|Win32.Build.0 = Debug|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|x64.ActiveCfg = Debug|x64 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|x64.Build.0 = Debug|x64 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|ARM.ActiveCfg = Release|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|Win32.ActiveCfg = Release|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|Win32.Build.0 = Release|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|x64.ActiveCfg = Release|x64 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|x64.Build.0 = Release|x64 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|ARM.ActiveCfg = Debug|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|Win32.ActiveCfg = Debug|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|Win32.Build.0 = Debug|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|x64.ActiveCfg = Debug|x64 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|x64.Build.0 = Debug|x64 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|ARM.ActiveCfg = Release|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|Win32.ActiveCfg = Release|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|Win32.Build.0 = Release|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|x64.ActiveCfg = Release|x64 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|x64.Build.0 = Release|x64 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|ARM.ActiveCfg = Debug|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|Win32.ActiveCfg = Debug|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|Win32.Build.0 = Debug|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|x64.ActiveCfg = Debug|x64 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|x64.Build.0 = Debug|x64 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|ARM.ActiveCfg = Release|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|Win32.ActiveCfg = Release|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|Win32.Build.0 = Release|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|x64.ActiveCfg = Release|x64 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|x64.Build.0 = Release|x64 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|ARM.ActiveCfg = Debug|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|Win32.ActiveCfg = Debug|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|Win32.Build.0 = Debug|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|x64.ActiveCfg = Debug|x64 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|x64.Build.0 = Debug|x64 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|ARM.ActiveCfg = Release|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|Win32.ActiveCfg = Release|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|Win32.Build.0 = Release|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|x64.ActiveCfg = Release|x64 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|x64.Build.0 = Release|x64 - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Debug|ARM.ActiveCfg = Debug|ARM - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Debug|ARM.Build.0 = Debug|ARM - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Debug|ARM.Deploy.0 = Debug|ARM - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Debug|Win32.ActiveCfg = Debug|Win32 - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Debug|Win32.Build.0 = Debug|Win32 - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Debug|Win32.Deploy.0 = Debug|Win32 - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Debug|x64.ActiveCfg = Debug|x64 - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Debug|x64.Build.0 = Debug|x64 - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Debug|x64.Deploy.0 = Debug|x64 - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Release|ARM.ActiveCfg = Release|ARM - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Release|ARM.Build.0 = Release|ARM - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Release|ARM.Deploy.0 = Release|ARM - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Release|Win32.ActiveCfg = Release|Win32 - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Release|Win32.Build.0 = Release|Win32 - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Release|Win32.Deploy.0 = Release|Win32 - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Release|x64.ActiveCfg = Release|x64 - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Release|x64.Build.0 = Release|x64 - {1C20F771-3131-46E8-805F-AA1FE44165C0}.Release|x64.Deploy.0 = Release|x64 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|ARM.ActiveCfg = Debug|ARM - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|ARM.Build.0 = Debug|ARM - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|ARM.Deploy.0 = Debug|ARM - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|Win32.ActiveCfg = Debug|Win32 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|Win32.Build.0 = Debug|Win32 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|Win32.Deploy.0 = Debug|Win32 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|x64.ActiveCfg = Debug|x64 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|x64.Build.0 = Debug|x64 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|x64.Deploy.0 = Debug|x64 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|ARM.ActiveCfg = Release|ARM - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|ARM.Build.0 = Release|ARM - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|ARM.Deploy.0 = Release|ARM - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|Win32.ActiveCfg = Release|Win32 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|Win32.Build.0 = Release|Win32 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|Win32.Deploy.0 = Release|Win32 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|x64.ActiveCfg = Release|x64 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|x64.Build.0 = Release|x64 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|x64.Deploy.0 = Release|x64 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|ARM.ActiveCfg = Debug|ARM - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|ARM.Build.0 = Debug|ARM - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|ARM.Deploy.0 = Debug|ARM - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|Win32.ActiveCfg = Debug|Win32 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|Win32.Build.0 = Debug|Win32 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|Win32.Deploy.0 = Debug|Win32 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|x64.ActiveCfg = Debug|x64 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|x64.Build.0 = Debug|x64 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|x64.Deploy.0 = Debug|x64 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|ARM.ActiveCfg = Release|ARM - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|ARM.Build.0 = Release|ARM - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|ARM.Deploy.0 = Release|ARM - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|Win32.ActiveCfg = Release|Win32 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|Win32.Build.0 = Release|Win32 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|Win32.Deploy.0 = Release|Win32 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|x64.ActiveCfg = Release|x64 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|x64.Build.0 = Release|x64 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|x64.Deploy.0 = Release|x64 - {BA4F15A0-6F9C-4ED6-A132-D6F7D0E08D6A}.Debug|ARM.ActiveCfg = Debug|ARM - {BA4F15A0-6F9C-4ED6-A132-D6F7D0E08D6A}.Debug|ARM.Build.0 = Debug|ARM - {BA4F15A0-6F9C-4ED6-A132-D6F7D0E08D6A}.Debug|Win32.ActiveCfg = Debug|Win32 - {BA4F15A0-6F9C-4ED6-A132-D6F7D0E08D6A}.Debug|Win32.Build.0 = Debug|Win32 - {BA4F15A0-6F9C-4ED6-A132-D6F7D0E08D6A}.Debug|x64.ActiveCfg = Debug|x64 - {BA4F15A0-6F9C-4ED6-A132-D6F7D0E08D6A}.Debug|x64.Build.0 = Debug|x64 - {BA4F15A0-6F9C-4ED6-A132-D6F7D0E08D6A}.Release|ARM.ActiveCfg = Release|ARM - {BA4F15A0-6F9C-4ED6-A132-D6F7D0E08D6A}.Release|ARM.Build.0 = Release|ARM - {BA4F15A0-6F9C-4ED6-A132-D6F7D0E08D6A}.Release|Win32.ActiveCfg = Release|Win32 - {BA4F15A0-6F9C-4ED6-A132-D6F7D0E08D6A}.Release|Win32.Build.0 = Release|Win32 - {BA4F15A0-6F9C-4ED6-A132-D6F7D0E08D6A}.Release|x64.ActiveCfg = Release|x64 - {BA4F15A0-6F9C-4ED6-A132-D6F7D0E08D6A}.Release|x64.Build.0 = Release|x64 - {CF74448D-FE99-4E3C-AFA6-A50F3145BAF3}.Debug|ARM.ActiveCfg = DebugStatic|ARM - {CF74448D-FE99-4E3C-AFA6-A50F3145BAF3}.Debug|ARM.Build.0 = DebugStatic|ARM - {CF74448D-FE99-4E3C-AFA6-A50F3145BAF3}.Debug|Win32.ActiveCfg = DebugStatic|Win32 - {CF74448D-FE99-4E3C-AFA6-A50F3145BAF3}.Debug|Win32.Build.0 = DebugStatic|Win32 - {CF74448D-FE99-4E3C-AFA6-A50F3145BAF3}.Debug|x64.ActiveCfg = DebugStatic|x64 - {CF74448D-FE99-4E3C-AFA6-A50F3145BAF3}.Debug|x64.Build.0 = DebugStatic|x64 - {CF74448D-FE99-4E3C-AFA6-A50F3145BAF3}.Release|ARM.ActiveCfg = ReleaseStatic|ARM - {CF74448D-FE99-4E3C-AFA6-A50F3145BAF3}.Release|ARM.Build.0 = ReleaseStatic|ARM - {CF74448D-FE99-4E3C-AFA6-A50F3145BAF3}.Release|Win32.ActiveCfg = ReleaseStatic|Win32 - {CF74448D-FE99-4E3C-AFA6-A50F3145BAF3}.Release|Win32.Build.0 = ReleaseStatic|Win32 - {CF74448D-FE99-4E3C-AFA6-A50F3145BAF3}.Release|x64.ActiveCfg = ReleaseStatic|x64 - {CF74448D-FE99-4E3C-AFA6-A50F3145BAF3}.Release|x64.Build.0 = ReleaseStatic|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {65951C40-A332-4B54-89C2-7CDAF30D5F66} = {E25A1A01-9AB0-41C5-A03B-F6B83F5E66B9} - {594DCB5F-07E3-4084-A2CE-268611FA629F} = {E25A1A01-9AB0-41C5-A03B-F6B83F5E66B9} - {3D5908F7-7673-4229-BC46-2007A7AF9CAE} = {E25A1A01-9AB0-41C5-A03B-F6B83F5E66B9} - {F40F4804-50F9-4257-8D74-B9CBB19AC4C3} = {E25A1A01-9AB0-41C5-A03B-F6B83F5E66B9} - {0A9BA181-7876-4B3D-A5E0-EE673FA51C05} = {E25A1A01-9AB0-41C5-A03B-F6B83F5E66B9} - {01A76234-E6E8-4332-9FE2-1E12C34621BE} = {E25A1A01-9AB0-41C5-A03B-F6B83F5E66B9} - {9AD285A2-301E-47A0-A299-14AD5D4F2758} = {E25A1A01-9AB0-41C5-A03B-F6B83F5E66B9} - {15F3B200-1AED-4B57-AF37-B21CD67914B1} = {E25A1A01-9AB0-41C5-A03B-F6B83F5E66B9} - {C5D88D15-F9F5-48E2-9EF2-BE0B645B9C0D} = {E25A1A01-9AB0-41C5-A03B-F6B83F5E66B9} - {E5F8A2F0-F713-4673-A42F-2CC4E8FB171B} = {E25A1A01-9AB0-41C5-A03B-F6B83F5E66B9} - {06A71AA7-132E-4A1B-A353-C36B2779331F} = {B27A3D67-1423-48D8-9F6D-D8FD7E682EC7} - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D} = {06A71AA7-132E-4A1B-A353-C36B2779331F} - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1} = {06A71AA7-132E-4A1B-A353-C36B2779331F} - {CA4D2B5D-D78C-4165-B8E6-0126FF584FCB} = {B27A3D67-1423-48D8-9F6D-D8FD7E682EC7} - {F03BEE03-BEFB-4B17-A774-D9C8246530D4} = {CA4D2B5D-D78C-4165-B8E6-0126FF584FCB} - {BBB2B70F-1D96-4597-96B0-75EA9BE3CA2A} = {B27A3D67-1423-48D8-9F6D-D8FD7E682EC7} - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147} = {BBB2B70F-1D96-4597-96B0-75EA9BE3CA2A} - {843B16ED-DE6A-4541-B700-D65B384D43A0} = {B27A3D67-1423-48D8-9F6D-D8FD7E682EC7} - {E442BD21-6B65-4D0E-A96C-623F605A9517} = {843B16ED-DE6A-4541-B700-D65B384D43A0} - {3D3149CF-B1FF-40C0-BD59-1B41FC3522F0} = {843B16ED-DE6A-4541-B700-D65B384D43A0} - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7} = {E442BD21-6B65-4D0E-A96C-623F605A9517} - {84350CD1-D406-4A4F-9571-261CA46D77C5} = {3D3149CF-B1FF-40C0-BD59-1B41FC3522F0} - {052831C4-6B41-4A52-A740-4228EB79CF3B} = {B27A3D67-1423-48D8-9F6D-D8FD7E682EC7} - {1C20F771-3131-46E8-805F-AA1FE44165C0} = {052831C4-6B41-4A52-A740-4228EB79CF3B} - {11041CA3-4C29-41E4-9C76-36AF06268C19} = {843B16ED-DE6A-4541-B700-D65B384D43A0} - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79} = {11041CA3-4C29-41E4-9C76-36AF06268C19} - {3E5DF179-3668-49DA-9B6D-38C0632D8F28} = {B27A3D67-1423-48D8-9F6D-D8FD7E682EC7} - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658} = {3E5DF179-3668-49DA-9B6D-38C0632D8F28} - {BA4F15A0-6F9C-4ED6-A132-D6F7D0E08D6A} = {E25A1A01-9AB0-41C5-A03B-F6B83F5E66B9} - {CF74448D-FE99-4E3C-AFA6-A50F3145BAF3} = {E25A1A01-9AB0-41C5-A03B-F6B83F5E66B9} - EndGlobalSection -EndGlobal diff --git a/setup_ps_env_VS2013.ps1 b/setup_ps_env_VS2013.ps1 deleted file mode 100644 index 085175864f..0000000000 --- a/setup_ps_env_VS2013.ps1 +++ /dev/null @@ -1,22 +0,0 @@ -function Get-Batchfile ($file) { - $cmd = "`"$file`" & set" - cmd /c $cmd | Foreach-Object { - $p, $v = $_.split('=') - Set-Item -path env:$p -value $v - } -} - -function VsVars32() -{ - $vs120comntools = (Get-ChildItem env:VS120COMNTOOLS).Value - $batchFile = [System.IO.Path]::Combine($vs120comntools, "vsvars32.bat") - Get-Batchfile $BatchFile -} - -"Initializing C++ REST SDK Powershell VS2013 Environment" - -# get VS tools -VsVars32 - -$Env:VisualStudioVersion = "12.0" -$Env:DevToolsVersion = "120" diff --git a/setup_ps_env_VS2015.ps1 b/setup_ps_env_VS2015.ps1 deleted file mode 100644 index 297f210e32..0000000000 --- a/setup_ps_env_VS2015.ps1 +++ /dev/null @@ -1,17 +0,0 @@ -"Initializing C++ REST SDK Powershell VS2015 Environment" - -# Add MSBuild to the path. -if (Test-Path "Env:ProgramFiles(x86)") -{ - $msbuildLocation = (Get-ChildItem "Env:ProgramFiles(x86)").Value -} -else -{ - $msbuildLocation = (Get-ChildItem "Env:ProgramFiles").Value -} - -$msbuildLocation = [System.IO.Path]::Combine($msbuildLocation, "MSBuild", "14.0", "Bin") -$Env:Path += ";" + $msbuildLocation - -$Env:VisualStudioVersion = "14.0" -$Env:DevToolsVersion = "140" From 11bc9f0697741e50cc2616a9684eb91062eb4985 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 18 Oct 2017 23:51:06 -0700 Subject: [PATCH 130/438] Remove debug message. --- Release/cmake/cpprest_find_boost.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/Release/cmake/cpprest_find_boost.cmake b/Release/cmake/cpprest_find_boost.cmake index 9e8db2948a..69b07964c5 100644 --- a/Release/cmake/cpprest_find_boost.cmake +++ b/Release/cmake/cpprest_find_boost.cmake @@ -42,7 +42,6 @@ function(cpprest_find_boost) endif() set(_prev "${_lib}") endforeach() - message(STATUS "_libs: ${_libs}") target_link_libraries(cpprestsdk_boost_internal INTERFACE "$") else() From c1a4067d82f07a218a9f71fb68badac05afff9e8 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 18 Oct 2017 23:51:21 -0700 Subject: [PATCH 131/438] Fix _do_while patch on Linux. --- Release/include/cpprest/astreambuf.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Release/include/cpprest/astreambuf.h b/Release/include/cpprest/astreambuf.h index d4769f7aa9..cca1abc9cb 100644 --- a/Release/include/cpprest/astreambuf.h +++ b/Release/include/cpprest/astreambuf.h @@ -27,10 +27,10 @@ namespace Concurrency namespace details { template - task _do_while(std::function(void)> func) + pplx::task _do_while(std::function(void)> func) { - task first = func(); - return first.then([=](bool guard) -> task { + pplx::task first = func(); + return first.then([=](bool guard) -> pplx::task { if (guard) return Concurrency::details::_do_while(func); else From e5350bac8904286c5b309139cf39c5b543e12e2e Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 18 Oct 2017 23:54:36 -0700 Subject: [PATCH 132/438] Always add CMAKE_DL_LIBS to test_runner. --- Release/tests/common/TestRunner/CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Release/tests/common/TestRunner/CMakeLists.txt b/Release/tests/common/TestRunner/CMakeLists.txt index a39f76800a..ec74598dee 100644 --- a/Release/tests/common/TestRunner/CMakeLists.txt +++ b/Release/tests/common/TestRunner/CMakeLists.txt @@ -7,10 +7,9 @@ if (WIN32) endif() add_executable(test_runner test_runner.cpp test_module_loader.cpp) -target_link_libraries(test_runner PRIVATE unittestpp) +target_link_libraries(test_runner PRIVATE unittestpp ${CMAKE_DL_LIBS}) if(BUILD_SHARED_LIBS) - target_link_libraries(test_runner PRIVATE ${CMAKE_DL_LIBS}) elseif(APPLE) target_link_libraries(test_runner PRIVATE -Wl,-force_load httpclient_test @@ -22,7 +21,7 @@ elseif(APPLE) -Wl,-force_load utils_test ) elseif(UNIX) - target_link_libraries(test_runner PRIVATE ${CMAKE_DL_LIBS} + target_link_libraries(test_runner PRIVATE -Wl,--whole-archive httpclient_test json_test From 6c8f948e4d63bcd014f0ea6e6d5cc35713916ef9 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 19 Oct 2017 01:34:23 -0700 Subject: [PATCH 133/438] Fix outside tests to use the more stable badssl.com --- Release/tests/functional/http/client/outside_tests.cpp | 9 +++++---- .../websockets/client/authentication_tests.cpp | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Release/tests/functional/http/client/outside_tests.cpp b/Release/tests/functional/http/client/outside_tests.cpp index 4ac5a23632..56825fa00d 100644 --- a/Release/tests/functional/http/client/outside_tests.cpp +++ b/Release/tests/functional/http/client/outside_tests.cpp @@ -151,6 +151,7 @@ TEST_FIXTURE(uri_address, no_transfer_encoding_content_length) } // Note additional sites for testing can be found at: +// https://badssl.com/ // https://www.ssllabs.com/ssltest/ // http://www.internetsociety.org/deploy360/resources/dane-test-sites/ // https://onlinessl.netlock.hu/# @@ -158,17 +159,17 @@ TEST(server_selfsigned_cert) { handle_timeout([] { - http_client client(U("https://www.pcwebshop.co.uk/")); + http_client client(U("https://self-signed.badssl.com/")); auto requestTask = client.request(methods::GET); VERIFY_THROWS(requestTask.get(), http_exception); }); } -TEST(server_hostname_mismatch, "Ignore", "Site fixed certificate. Improve test (new site or alternate method).") +TEST(server_hostname_mismatch) { handle_timeout([] { - http_client client(U("https://swordsoftruth.com/")); + http_client client(U("https://wrong.host.badssl.com/")); auto requestTask = client.request(methods::GET); VERIFY_THROWS(requestTask.get(), http_exception); }); @@ -180,7 +181,7 @@ TEST(server_cert_expired) { http_client_config config; config.set_timeout(std::chrono::seconds(1)); - http_client client(U("https://tv.eurosport.com/"), config); + http_client client(U("https://expired.badssl.com/"), config); auto requestTask = client.request(methods::GET); VERIFY_THROWS(requestTask.get(), http_exception); }); diff --git a/Release/tests/functional/websockets/client/authentication_tests.cpp b/Release/tests/functional/websockets/client/authentication_tests.cpp index c04a90e1e0..5db5207697 100644 --- a/Release/tests/functional/websockets/client/authentication_tests.cpp +++ b/Release/tests/functional/websockets/client/authentication_tests.cpp @@ -219,17 +219,17 @@ void handshake_error_test_impl(const ::utility::string_t &host) TEST(self_signed_cert) { - handshake_error_test_impl(U("wss://www.pcwebshop.co.uk/")); + handshake_error_test_impl(U("wss://self-signed.badssl.com/")); } TEST(hostname_mismatch) { - handshake_error_test_impl(U("wss://jabbr.net")); + handshake_error_test_impl(U("wss://wrong.host.badssl.com/")); } TEST(cert_expired) { - handshake_error_test_impl(U("wss://tv.eurosport.com/")); + handshake_error_test_impl(U("wss://expired.badssl.com/")); } #endif From 272fa31defbfead731a3067d015dc6768f051e13 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 19 Oct 2017 02:19:21 -0700 Subject: [PATCH 134/438] Fix use-after-free race condition in winhttp. Essentially, the request_context could call ->finish() (and free itself) before the final WinHttp callback completed. The fix, without changing lifetime semantics, is to use a heap-allocated weak_ptr as the context. This weak_ptr will be freed by the callback function when called with WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING. --- .../src/http/client/http_client_winhttp.cpp | 579 ++++++++++-------- Release/src/pch/stdafx.h | 1 + 2 files changed, 311 insertions(+), 269 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 0054b8f839..60a4d060d5 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -187,10 +187,9 @@ class winhttp_request_context : public request_context // Factory function to create requests on the heap. static std::shared_ptr create_request_context(const std::shared_ptr<_http_client_communicator> &client, const http_request &request) { - // With WinHttp we have to pass the request context to the callback through a raw pointer. - // The lifetime of this object is delete once complete or report_error/report_exception is called. - auto pContext = new winhttp_request_context(client, request); - return std::shared_ptr(pContext, [](winhttp_request_context *){}); + std::shared_ptr ret(new winhttp_request_context(client, request)); + ret->m_self_reference = ret; + return std::move(ret); } ~winhttp_request_context() @@ -220,6 +219,7 @@ class winhttp_request_context : public request_context } HINTERNET m_request_handle; + std::weak_ptr* m_request_context; bool m_proxy_authentication_tried; bool m_server_authentication_tried; @@ -239,8 +239,9 @@ class winhttp_request_context : public request_context return m_readStream.streambuf(); } + // This self reference will keep us alive until finish() is called. + std::shared_ptr m_self_reference; memory_holder m_body_data; - std::unique_ptr decompressor; virtual void cleanup() @@ -258,7 +259,9 @@ class winhttp_request_context : public request_context virtual void finish() { request_context::finish(); - delete this; + assert(m_self_reference != nullptr); + auto dereference_self = std::move(m_self_reference); + // As the stack frame cleans up, this will be deleted if no other references exist. } private: @@ -267,6 +270,7 @@ class winhttp_request_context : public request_context winhttp_request_context(const std::shared_ptr<_http_client_communicator> &client, const http_request &request) : request_context(client, request), m_request_handle(nullptr), + m_request_context(nullptr), m_bodyType(no_body), m_startingPosition(std::char_traits::eof()), m_body_data(), @@ -572,7 +576,8 @@ class winhttp_client : public _http_client_communicator void send_request(_In_ const std::shared_ptr &request) { http_request &msg = request->m_request; - winhttp_request_context * winhttp_context = static_cast(request.get()); + std::shared_ptr winhttp_context = std::static_pointer_cast(request); + std::weak_ptr weak_winhttp_context = winhttp_context; proxy_info info; bool proxy_info_required = false; @@ -747,11 +752,13 @@ class winhttp_client : public _http_client_communicator if(msg._cancellation_token() != pplx::cancellation_token::none()) { // cancellation callback is unregistered when request is completed. - winhttp_context->m_cancellationRegistration = msg._cancellation_token().register_callback([winhttp_context]() + winhttp_context->m_cancellationRegistration = msg._cancellation_token().register_callback([weak_winhttp_context]() { // Call the WinHttpSendRequest API after WinHttpCloseHandle will give invalid handle error and we throw this exception. // Call the cleanup to make the m_request_handle as nullptr, otherwise, Application Verifier will give AV exception on m_request_handle. - winhttp_context->cleanup(); + auto lock = weak_winhttp_context.lock(); + if (!lock) return; + lock->cleanup(); }); } @@ -779,8 +786,16 @@ class winhttp_client : public _http_client_communicator private: - void _start_request_send(_In_ winhttp_request_context * winhttp_context, size_t content_length) + void _start_request_send(const std::shared_ptr& winhttp_context, size_t content_length) { + // WinHttp takes a context object as a void*. We therefore heap allocate a std::weak_ptr to the request context which will be destroyed during the final callback. + std::unique_ptr> weak_context_holder; + if (winhttp_context->m_request_context == nullptr) + { + weak_context_holder = std::make_unique>(winhttp_context); + winhttp_context->m_request_context = weak_context_holder.get(); + } + if (winhttp_context->m_bodyType == no_body) { if(!WinHttpSendRequest( @@ -790,11 +805,19 @@ class winhttp_client : public _http_client_communicator nullptr, 0, 0, - (DWORD_PTR)winhttp_context)) + (DWORD_PTR)winhttp_context->m_request_context)) { + if (weak_context_holder) + winhttp_context->m_request_context = nullptr; + auto errorCode = GetLastError(); winhttp_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpSendRequest")); } + else + { + // Ownership of the weak_context_holder was accepted by the callback, so release the pointer without freeing. + weak_context_holder.release(); + } return; } @@ -815,11 +838,19 @@ class winhttp_client : public _http_client_communicator nullptr, 0, winhttp_context->m_bodyType == content_length_chunked ? (DWORD)content_length : WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, - (DWORD_PTR)winhttp_context)) + (DWORD_PTR)winhttp_context->m_request_context)) { + if (weak_context_holder) + winhttp_context->m_request_context = nullptr; + auto errorCode = GetLastError(); winhttp_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpSendRequest chunked")); } + else + { + // Ownership of the weak_context_holder was accepted by the callback, so release the pointer without freeing. + weak_context_holder.release(); + } } // Helper function to query/read next part of response data from winhttp. @@ -1011,7 +1042,7 @@ class winhttp_client : public _http_client_communicator // or false if we fail to handle. static bool handle_authentication_failure( HINTERNET hRequestHandle, - _In_ winhttp_request_context * p_request_context, + const std::shared_ptr& p_request_context, _In_ DWORD error = 0) { http_request & request = p_request_context->m_request; @@ -1132,261 +1163,250 @@ class winhttp_client : public _http_client_communicator { CASABLANCA_UNREFERENCED_PARAMETER(statusInfoLength); - if ( statusCode == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING ) + std::weak_ptr* p_weak_request_context = reinterpret_cast *>(context); + + if (p_weak_request_context == nullptr) return; - winhttp_request_context * p_request_context = reinterpret_cast(context); + if (statusCode == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) + { + // This callback is responsible for freeing the type-erased context. + // This particular status code indicates that this is the final callback call, suitable for context destruction. + delete p_weak_request_context; + return; + } - if(p_request_context != nullptr) + auto p_request_context = p_weak_request_context->lock(); + if (!p_request_context) + // The request context was already released, probably due to cancellation + return; + + switch (statusCode) { - switch (statusCode) + case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR : { - case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR : + WINHTTP_ASYNC_RESULT *error_result = reinterpret_cast(statusInfo); + const DWORD errorCode = error_result->dwError; + + // Some authentication schemes require multiple transactions. + // When ERROR_WINHTTP_RESEND_REQUEST is encountered, + // we should continue to resend the request until a response is received that does not contain a 401 or 407 status code. + if (errorCode == ERROR_WINHTTP_RESEND_REQUEST) { - WINHTTP_ASYNC_RESULT *error_result = reinterpret_cast(statusInfo); - const DWORD errorCode = error_result->dwError; + bool resending = handle_authentication_failure(hRequestHandle, p_request_context, errorCode); + if(resending) + { + // The request is resending. Wait until we get a new response. + return; + } + } - // Some authentication schemes require multiple transactions. - // When ERROR_WINHTTP_RESEND_REQUEST is encountered, - // we should continue to resend the request until a response is received that does not contain a 401 or 407 status code. - if (errorCode == ERROR_WINHTTP_RESEND_REQUEST) + p_request_context->report_error(errorCode, build_error_msg(error_result)); + break; + } + case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE : + { + if (!p_request_context->m_request.body()) + { + // Report progress finished uploading with no message body. + auto progress = p_request_context->m_request._get_impl()->_progress_handler(); + if ( progress ) { - bool resending = handle_authentication_failure(hRequestHandle, p_request_context, errorCode); - if(resending) + try { (*progress)(message_direction::upload, 0); } catch(...) { - // The request is resending. Wait until we get a new response. + p_request_context->report_exception(std::current_exception()); return; } } + } - p_request_context->report_error(errorCode, build_error_msg(error_result)); - break; + if ( p_request_context->m_bodyType == transfer_encoding_chunked ) + { + _transfer_encoding_chunked_write_data(p_request_context.get()); } - case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE : + else if ( p_request_context->m_bodyType == content_length_chunked ) { - if (!p_request_context->m_request.body()) + _multiple_segment_write_data(p_request_context.get()); + } + else + { + if(!WinHttpReceiveResponse(hRequestHandle, nullptr)) { - // Report progress finished uploading with no message body. - auto progress = p_request_context->m_request._get_impl()->_progress_handler(); - if ( progress ) - { - try { (*progress)(message_direction::upload, 0); } catch(...) - { - p_request_context->report_exception(std::current_exception()); - return; - } - } + auto errorCode = GetLastError(); + p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpReceiveResponse")); } + } + break; + } + case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE: + { + auto *flagsPtr = reinterpret_cast(statusInfo); + auto flags = *flagsPtr; + + std::string err = "SSL error: "; + if (flags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED) err += "WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED failed to check revocation status. "; + if (flags & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT) err += "WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT SSL certificate is invalid. "; + if (flags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED) err += "WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED SSL certificate was revoked. "; + if (flags & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA) err += "WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA SSL invalid CA. "; + if (flags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID) err += "WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID SSL common name does not match. "; + if (flags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID) err += "WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID SLL certificate is expired. "; + if (flags & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR) err += "WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR internal error. "; + + p_request_context->report_exception(web::http::http_exception(std::move(err))); + break; + } + case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE : + { + DWORD bytesWritten = *((DWORD *)statusInfo); + _ASSERTE(statusInfoLength == sizeof(DWORD)); - if ( p_request_context->m_bodyType == transfer_encoding_chunked ) - { - _transfer_encoding_chunked_write_data(p_request_context); - } - else if ( p_request_context->m_bodyType == content_length_chunked ) - { - _multiple_segment_write_data(p_request_context); - } - else + if ( bytesWritten > 0 ) + { + auto progress = p_request_context->m_request._get_impl()->_progress_handler(); + if ( progress ) { - if(!WinHttpReceiveResponse(hRequestHandle, nullptr)) + p_request_context->m_uploaded += bytesWritten; + try { (*progress)(message_direction::upload, p_request_context->m_uploaded); } catch(...) { - auto errorCode = GetLastError(); - p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpReceiveResponse")); + p_request_context->report_exception(std::current_exception()); + return; } } - break; } - case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE: - { - auto *flagsPtr = reinterpret_cast(statusInfo); - auto flags = *flagsPtr; - - std::string err = "SSL error: "; - if (flags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED) err += "WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED failed to check revocation status. "; - if (flags & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT) err += "WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT SSL certificate is invalid. "; - if (flags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED) err += "WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED SSL certificate was revoked. "; - if (flags & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA) err += "WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA SSL invalid CA. "; - if (flags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID) err += "WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID SSL common name does not match. "; - if (flags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID) err += "WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID SLL certificate is expired. "; - if (flags & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR) err += "WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR internal error. "; - - p_request_context->report_exception(std::runtime_error(err)); - break; - } - case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE : + + if ( p_request_context->is_externally_allocated() ) { - DWORD bytesWritten = *((DWORD *)statusInfo); - _ASSERTE(statusInfoLength == sizeof(DWORD)); + p_request_context->_get_readbuffer().release(p_request_context->m_body_data.get(), bytesWritten); + } - if ( bytesWritten > 0 ) + if ( p_request_context->m_bodyType == transfer_encoding_chunked ) + { + _transfer_encoding_chunked_write_data(p_request_context.get()); + } + else if ( p_request_context->m_bodyType == content_length_chunked ) + { + _multiple_segment_write_data(p_request_context.get()); + } + else + { + if(!WinHttpReceiveResponse(hRequestHandle, nullptr)) { - auto progress = p_request_context->m_request._get_impl()->_progress_handler(); - if ( progress ) - { - p_request_context->m_uploaded += bytesWritten; - try { (*progress)(message_direction::upload, p_request_context->m_uploaded); } catch(...) - { - p_request_context->report_exception(std::current_exception()); - return; - } - } + auto errorCode = GetLastError(); + p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpReceiveResponse")); } + } + break; + } + case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE : + { + // First need to query to see what the headers size is. + DWORD headerBufferLength = 0; + query_header_length(hRequestHandle, WINHTTP_QUERY_RAW_HEADERS_CRLF, headerBufferLength); + + // Now allocate buffer for headers and query for them. + std::vector header_raw_buffer; + header_raw_buffer.resize(headerBufferLength); + utf16char * header_buffer = reinterpret_cast(&header_raw_buffer[0]); + if(!WinHttpQueryHeaders( + hRequestHandle, + WINHTTP_QUERY_RAW_HEADERS_CRLF, + WINHTTP_HEADER_NAME_BY_INDEX, + header_buffer, + &headerBufferLength, + WINHTTP_NO_HEADER_INDEX)) + { + auto errorCode = GetLastError(); + p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpQueryHeaders"));; + return; + } - if ( p_request_context->is_externally_allocated() ) - { - p_request_context->_get_readbuffer().release(p_request_context->m_body_data.get(), bytesWritten); - } + http_response & response = p_request_context->m_response; + parse_winhttp_headers(hRequestHandle, header_buffer, response); - if ( p_request_context->m_bodyType == transfer_encoding_chunked ) - { - _transfer_encoding_chunked_write_data(p_request_context); - } - else if ( p_request_context->m_bodyType == content_length_chunked ) - { - _multiple_segment_write_data(p_request_context); - } - else - { - if(!WinHttpReceiveResponse(hRequestHandle, nullptr)) - { - auto errorCode = GetLastError(); - p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpReceiveResponse")); - } - } - break; - } - case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE : + if(response.status_code() == status_codes::Unauthorized /*401*/ || + response.status_code() == status_codes::ProxyAuthRequired /*407*/) { - // First need to query to see what the headers size is. - DWORD headerBufferLength = 0; - query_header_length(hRequestHandle, WINHTTP_QUERY_RAW_HEADERS_CRLF, headerBufferLength); - - // Now allocate buffer for headers and query for them. - std::vector header_raw_buffer; - header_raw_buffer.resize(headerBufferLength); - utf16char * header_buffer = reinterpret_cast(&header_raw_buffer[0]); - if(!WinHttpQueryHeaders( - hRequestHandle, - WINHTTP_QUERY_RAW_HEADERS_CRLF, - WINHTTP_HEADER_NAME_BY_INDEX, - header_buffer, - &headerBufferLength, - WINHTTP_NO_HEADER_INDEX)) + bool resending = handle_authentication_failure(hRequestHandle, p_request_context); + if(resending) { - auto errorCode = GetLastError(); - p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpQueryHeaders"));; + // The request was not completed but resent with credentials. Wait until we get a new response return; } + } - http_response & response = p_request_context->m_response; - parse_winhttp_headers(hRequestHandle, header_buffer, response); + // If the response body is compressed we will read the encoding header and create a decompressor object which will later decompress the body + utility::string_t encoding; + if (web::http::details::compression::stream_decompressor::is_supported() && response.headers().match(web::http::header_names::content_encoding, encoding)) + { + auto alg = web::http::details::compression::stream_decompressor::to_compression_algorithm(encoding); - if(response.status_code() == status_codes::Unauthorized /*401*/ || - response.status_code() == status_codes::ProxyAuthRequired /*407*/) + if (alg != web::http::details::compression::compression_algorithm::invalid) { - bool resending = handle_authentication_failure(hRequestHandle, p_request_context); - if(resending) - { - // The request was not completed but resent with credentials. Wait until we get a new response - return; - } + p_request_context->decompressor = std::make_unique(alg); } - - // If the response body is compressed we will read the encoding header and create a decompressor object which will later decompress the body - utility::string_t encoding; - if (web::http::details::compression::stream_decompressor::is_supported() && response.headers().match(web::http::header_names::content_encoding, encoding)) + else { - auto alg = web::http::details::compression::stream_decompressor::to_compression_algorithm(encoding); - - if (alg != web::http::details::compression::compression_algorithm::invalid) - { - p_request_context->decompressor = std::make_unique(alg); - } - else - { - utility::string_t error = U("Unsupported compression algorithm in the Content Encoding header: "); - error += encoding; - p_request_context->report_exception(http_exception(error)); - } + utility::string_t error = U("Unsupported compression algorithm in the Content Encoding header: "); + error += encoding; + p_request_context->report_exception(http_exception(error)); } + } - // Signal that the headers are available. - p_request_context->complete_headers(); + // Signal that the headers are available. + p_request_context->complete_headers(); - // If the method was 'HEAD,' the body of the message is by definition empty. No need to - // read it. Any headers that suggest the presence of a body can safely be ignored. - if (p_request_context->m_request.method() == methods::HEAD ) - { - p_request_context->allocate_request_space(nullptr, 0); - p_request_context->complete_request(0); - return; - } + // If the method was 'HEAD,' the body of the message is by definition empty. No need to + // read it. Any headers that suggest the presence of a body can safely be ignored. + if (p_request_context->m_request.method() == methods::HEAD ) + { + p_request_context->allocate_request_space(nullptr, 0); + p_request_context->complete_request(0); + return; + } - // HTTP Specification states: - // If a message is received with both a Transfer-Encoding header field - // and a Content-Length header field, the latter MUST be ignored. - // If none of them is specified, the message length should be determined by the server closing the connection. - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4 + // HTTP Specification states: + // If a message is received with both a Transfer-Encoding header field + // and a Content-Length header field, the latter MUST be ignored. + // If none of them is specified, the message length should be determined by the server closing the connection. + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4 - read_next_response_chunk(p_request_context, 0, true); - break; - } - case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE : - { - // Status information contains pointer to DWORD containing number of bytes available. - const DWORD num_bytes = *(PDWORD)statusInfo; + read_next_response_chunk(p_request_context.get(), 0, true); + break; + } + case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE : + { + // Status information contains pointer to DWORD containing number of bytes available. + const DWORD num_bytes = *(PDWORD)statusInfo; - if(num_bytes > 0) + if(num_bytes > 0) + { + if (p_request_context->decompressor) { - if (p_request_context->decompressor) - { - // Decompression is too slow to reliably do on this callback. Therefore we need to store it now in order to decompress it at a later stage in the flow. - // However, we want to eventually use the writebuf to store the decompressed body. Therefore we'll store the compressed body as an internal allocation in the request_context - p_request_context->allocate_reply_space(nullptr, num_bytes); - } - else - { - auto writebuf = p_request_context->_get_writebuffer(); - p_request_context->allocate_reply_space(writebuf.alloc(num_bytes), num_bytes); - } - - // Read in body all at once. - if(!WinHttpReadData( - hRequestHandle, - p_request_context->m_body_data.get(), - num_bytes, - nullptr)) - { - auto errorCode = GetLastError(); - p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpReadData")); - } + // Decompression is too slow to reliably do on this callback. Therefore we need to store it now in order to decompress it at a later stage in the flow. + // However, we want to eventually use the writebuf to store the decompressed body. Therefore we'll store the compressed body as an internal allocation in the request_context + p_request_context->allocate_reply_space(nullptr, num_bytes); } else { - // No more data available, complete the request. - auto progress = p_request_context->m_request._get_impl()->_progress_handler(); - if (progress) - { - try { (*progress)(message_direction::download, p_request_context->m_downloaded); } - catch (...) - { - p_request_context->report_exception(std::current_exception()); - return; - } - } + auto writebuf = p_request_context->_get_writebuffer(); + p_request_context->allocate_reply_space(writebuf.alloc(num_bytes), num_bytes); + } - p_request_context->complete_request(p_request_context->m_downloaded); + // Read in body all at once. + if(!WinHttpReadData( + hRequestHandle, + p_request_context->m_body_data.get(), + num_bytes, + nullptr)) + { + auto errorCode = GetLastError(); + p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpReadData")); } - break; } - case WINHTTP_CALLBACK_STATUS_READ_COMPLETE : + else { - // Status information length contains the number of bytes read. - DWORD bytesRead = statusInfoLength; - - // Report progress about downloaded bytes. + // No more data available, complete the request. auto progress = p_request_context->m_request._get_impl()->_progress_handler(); - p_request_context->m_downloaded += statusInfoLength; if (progress) { try { (*progress)(message_direction::download, p_request_context->m_downloaded); } @@ -1397,75 +1417,96 @@ class winhttp_client : public _http_client_communicator } } - // If no bytes have been read, then this is the end of the response. - if (bytesRead == 0) + p_request_context->complete_request(p_request_context->m_downloaded); + } + break; + } + case WINHTTP_CALLBACK_STATUS_READ_COMPLETE : + { + // Status information length contains the number of bytes read. + DWORD bytesRead = statusInfoLength; + + // Report progress about downloaded bytes. + auto progress = p_request_context->m_request._get_impl()->_progress_handler(); + p_request_context->m_downloaded += statusInfoLength; + if (progress) + { + try { (*progress)(message_direction::download, p_request_context->m_downloaded); } + catch (...) { - p_request_context->complete_request(p_request_context->m_downloaded); - break; + p_request_context->report_exception(std::current_exception()); + return; } + } - auto writebuf = p_request_context->_get_writebuffer(); + // If no bytes have been read, then this is the end of the response. + if (bytesRead == 0) + { + p_request_context->complete_request(p_request_context->m_downloaded); + break; + } - // If we have compressed data it is stored in the local allocation of the p_request_context. We will store the decompressed buffer in the external allocation of the p_request_context. - if (p_request_context->decompressor) + auto writebuf = p_request_context->_get_writebuffer(); + + // If we have compressed data it is stored in the local allocation of the p_request_context. We will store the decompressed buffer in the external allocation of the p_request_context. + if (p_request_context->decompressor) + { + web::http::details::compression::data_buffer decompressed = p_request_context->decompressor->decompress(p_request_context->m_body_data.get(), bytesRead); + + if (p_request_context->decompressor->has_error()) + { + p_request_context->report_exception(std::runtime_error("Failed to decompress the response body")); + return; + } + + // We've decompressed this chunk of the body, need to now store it in the writebuffer. + auto decompressed_size = decompressed.size(); + + if (decompressed_size > 0) { - web::http::details::compression::data_buffer decompressed = p_request_context->decompressor->decompress(p_request_context->m_body_data.get(), bytesRead); + auto p = writebuf.alloc(decompressed_size); + p_request_context->allocate_reply_space(p, decompressed_size); + std::memcpy(p_request_context->m_body_data.get(), &decompressed[0], decompressed_size); + } + // Note, some servers seem to send a first chunk of body data that decompresses to nothing but initializes the zlib decryption state. This produces no decompressed output. + // Subsequent chunks will then begin emmiting decompressed body data. + + bytesRead = static_cast(decompressed_size); + } - if (p_request_context->decompressor->has_error()) + // If the data was allocated directly from the buffer then commit, otherwise we still + // need to write to the response stream buffer. + if (p_request_context->is_externally_allocated()) + { + writebuf.commit(bytesRead); + read_next_response_chunk(p_request_context.get(), bytesRead); + } + else + { + writebuf.putn_nocopy(p_request_context->m_body_data.get(), bytesRead).then( + [hRequestHandle, p_request_context, bytesRead] (pplx::task op) + { + size_t written = 0; + try { written = op.get(); } + catch (...) { - p_request_context->report_exception(std::runtime_error("Failed to decompress the response body")); + p_request_context->report_exception(std::current_exception()); return; } - // We've decompressed this chunk of the body, need to now store it in the writebuffer. - auto decompressed_size = decompressed.size(); - - if (decompressed_size > 0) + // If we couldn't write everything, it's time to exit. + if (written != bytesRead) { - auto p = writebuf.alloc(decompressed_size); - p_request_context->allocate_reply_space(p, decompressed_size); - std::memcpy(p_request_context->m_body_data.get(), &decompressed[0], decompressed_size); + p_request_context->report_exception(std::runtime_error("response stream unexpectedly failed to write the requested number of bytes")); + return; } - // Note, some servers seem to send a first chunk of body data that decompresses to nothing but initializes the zlib decryption state. This produces no decompressed output. - // Subsequent chunks will then begin emmiting decompressed body data. - bytesRead = static_cast(decompressed_size); - } - - // If the data was allocated directly from the buffer then commit, otherwise we still - // need to write to the response stream buffer. - if (p_request_context->is_externally_allocated()) - { - writebuf.commit(bytesRead); - read_next_response_chunk(p_request_context, bytesRead); - } - else - { - writebuf.putn_nocopy(p_request_context->m_body_data.get(), bytesRead).then( - [hRequestHandle, p_request_context, bytesRead] (pplx::task op) - { - size_t written = 0; - try { written = op.get(); } - catch (...) - { - p_request_context->report_exception(std::current_exception()); - return; - } - - // If we couldn't write everything, it's time to exit. - if (written != bytesRead) - { - p_request_context->report_exception(std::runtime_error("response stream unexpectedly failed to write the requested number of bytes")); - return; - } - - read_next_response_chunk(p_request_context, bytesRead); - }); - } - break; + read_next_response_chunk(p_request_context.get(), bytesRead); + }); } + break; } - } + } } // WinHTTP session and connection diff --git a/Release/src/pch/stdafx.h b/Release/src/pch/stdafx.h index 155b50b096..05a004dec4 100644 --- a/Release/src/pch/stdafx.h +++ b/Release/src/pch/stdafx.h @@ -88,6 +88,7 @@ #include #include #include +#include #include #include #include From 6e8d910e5839dea136f46ee7226f233378d5c3d9 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 19 Oct 2017 04:55:21 -0700 Subject: [PATCH 135/438] Fix auth_no_data test on linux. --- Release/tests/functional/http/client/authentication_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Release/tests/functional/http/client/authentication_tests.cpp b/Release/tests/functional/http/client/authentication_tests.cpp index 37b6177cc2..c58ca1c90c 100644 --- a/Release/tests/functional/http/client/authentication_tests.cpp +++ b/Release/tests/functional/http/client/authentication_tests.cpp @@ -646,7 +646,7 @@ TEST_FIXTURE(uri_address, failed_authentication_attempt, "Ignore:Linux", "89", " void auth_test_impl(bool fail) { std::string user("user1"), password("user1"); - auto return_code = status_codes::NotFound; // return 404 if successful auth + auto return_code = status_codes::OK; if (fail) { @@ -657,7 +657,7 @@ void auth_test_impl(bool fail) http_client_config client_config; web::credentials cred(U(user), U(password)); client_config.set_credentials(cred); - http_client client(U("http://test.webdav.org/auth-basic/"), client_config); + http_client client(U("http://httpbin.org/basic-auth/user1/user1"), client_config); http_response response = client.request(methods::GET).get(); VERIFY_ARE_EQUAL(return_code, response.status_code()); From 2b53b1b5e8c813d74279a5900c7b84dff5d44b6b Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 19 Oct 2017 04:55:42 -0700 Subject: [PATCH 136/438] Improve error diagnostics for VERIFY_THROWS_HTTP_ERROR_CODE --- .../http/utilities/include/http_asserts.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Release/tests/functional/http/utilities/include/http_asserts.h b/Release/tests/functional/http/utilities/include/http_asserts.h index 02eb702b0a..9291a936ce 100644 --- a/Release/tests/functional/http/utilities/include/http_asserts.h +++ b/Release/tests/functional/http/utilities/include/http_asserts.h @@ -202,7 +202,7 @@ class http_asserts #define HTTP_ERROR_CHECK_IMPL(__code) VERIFY_ARE_EQUAL(static_cast(__code), _exc.error_code().default_error_condition().value()); #endif #else -#define HTTP_ERROR_CHECK_IMPL(__code) if(__code != _exc.error_code()) { VERIFY_IS_TRUE(false, "Unexpected error code encountered."); } +#define HTTP_ERROR_CHECK_IMPL(__code) VERIFY_ARE_EQUAL(_exc.error_code(), __code, "Unexpected error code encountered.") #endif @@ -212,17 +212,20 @@ class http_asserts try \ { \ __expression; \ - VERIFY_IS_TRUE(false, "Expected http_exception not thrown"); \ + UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), "Expected exception: \"web::http::http_exception\" not thrown"); \ } \ catch (const web::http::http_exception& _exc) \ { \ VERIFY_IS_TRUE(std::string(_exc.what()).size() > 0); \ HTTP_ERROR_CHECK_IMPL(__code); \ - } \ - catch(...) \ - { \ - VERIFY_IS_TRUE(false, "Exception other than http_exception thrown"); \ - } \ + } catch(const std::exception & _exc) { \ + std::string _msg("(" #__expression ") threw exception: "); \ + _msg.append(_exc.what()); \ + UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), _msg.c_str()); \ + } catch (...) { \ + std::string _msg("(" #__expression ") threw exception: <...>"); \ + UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), _msg.c_str()); \ + } \ UNITTEST_MULTILINE_MACRO_END }}}} From 8b186cb76f223d4108cc3648419bae2a40c927b7 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 19 Oct 2017 04:59:31 -0700 Subject: [PATCH 137/438] Loosen tests because error codes can't be consistently reproduced on Linux. --- .../tests/functional/http/client/connections_and_errors.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Release/tests/functional/http/client/connections_and_errors.cpp b/Release/tests/functional/http/client/connections_and_errors.cpp index b535dc5a64..24e452f023 100644 --- a/Release/tests/functional/http/client/connections_and_errors.cpp +++ b/Release/tests/functional/http/client/connections_and_errors.cpp @@ -91,7 +91,7 @@ TEST_FIXTURE(uri_address, server_doesnt_exist) http_client_config config; config.set_timeout(std::chrono::seconds(1)); http_client client(m_uri, config); - VERIFY_THROWS_HTTP_ERROR_CODE(client.request(methods::GET).wait(), std::errc::host_unreachable); + VERIFY_THROWS(client.request(methods::GET).wait(), web::http::http_exception); } TEST_FIXTURE(uri_address, open_failure) @@ -125,7 +125,7 @@ TEST_FIXTURE(uri_address, server_close_without_responding) VERIFY_THROWS_HTTP_ERROR_CODE(response.wait(), std::errc::connection_aborted); // Try sending another request. - VERIFY_THROWS_HTTP_ERROR_CODE(client.request(methods::GET).wait(), std::errc::host_unreachable); + VERIFY_THROWS(client.request(methods::GET).wait(), web::http::http_exception); } TEST_FIXTURE(uri_address, request_timeout) From f08dd84c51a14686f2345a15f79705cefd28604e Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 19 Oct 2017 06:31:03 -0700 Subject: [PATCH 138/438] Add missing begin-quotes to http constants --- Release/include/cpprest/details/http_constants.dat | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Release/include/cpprest/details/http_constants.dat b/Release/include/cpprest/details/http_constants.dat index f3d051f236..c3b1a53cb6 100644 --- a/Release/include/cpprest/details/http_constants.dat +++ b/Release/include/cpprest/details/http_constants.dat @@ -51,11 +51,11 @@ DAT(UnsupportedMediaType, 415, _XPLATSTR("Unsupported Media Type")) DAT(RangeNotSatisfiable, 416, _XPLATSTR("Requested range not satisfiable")) DAT(ExpectationFailed, 417, _XPLATSTR("Expectation Failed")) DAT(MisdirectedRequest, 421, _XPLATSTR("Misdirected Request")) -DAT(UnprocessableEntity, 422, _XPLATSTR(Unprocessable Entity")) -DAT(Locked, 423, _XPLATSTR(Locked")) -DAT(FailedDependency, 424, _XPLATSTR(Failed Dependency")) -DAT(UpgradeRequired, 426, _XPLATSTR(Upgrade Required")) -DAT(PreconditionRequired, 428, _XPLATSTR(Precondition Required")) +DAT(UnprocessableEntity, 422, _XPLATSTR("Unprocessable Entity")) +DAT(Locked, 423, _XPLATSTR("Locked")) +DAT(FailedDependency, 424, _XPLATSTR("Failed Dependency")) +DAT(UpgradeRequired, 426, _XPLATSTR("Upgrade Required")) +DAT(PreconditionRequired, 428, _XPLATSTR("Precondition Required")) DAT(TooManyRequests, 429, _XPLATSTR("Too Many Requests")) DAT(RequestHeaderFieldsTooLarge, 431, _XPLATSTR("Request Header Fields Too Large")) DAT(UnavailableForLegalReasons, 451, _XPLATSTR("Unavailable For Legal Reasons")) From d305566190b927fe401b509eee9ec71c1f9790d1 Mon Sep 17 00:00:00 2001 From: Chris Deering Date: Thu, 19 Oct 2017 22:52:16 +0100 Subject: [PATCH 139/438] Fix an issue where requests sent via authenticated proxies could not be successfully redirected from one domain to another --- .../src/http/client/http_client_winhttp.cpp | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 60a4d060d5..5f1c5d2e90 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -1038,6 +1038,25 @@ class winhttp_client : public _http_client_communicator } } + static utility::string_t get_request_url(http://github.com/HINTERNET%20hRequestHandle) + { + DWORD urlSize{ 0 }; + if(FALSE == WinHttpQueryOption(hRequestHandle, WINHTTP_OPTION_URL, nullptr, &urlSize) || urlSize == 0) + { + return U(""); + } + + auto urlwchar = new WCHAR[urlSize / sizeof(WCHAR)]; + + WinHttpQueryOption(hRequestHandle, WINHTTP_OPTION_URL, (void*)urlwchar, &urlSize); + + utility::string_t url(http://github.com/urlwchar); + + delete[] urlwchar; + + return url; + } + // Returns true if we handle successfully and resending the request // or false if we fail to handle. static bool handle_authentication_failure( @@ -1094,10 +1113,22 @@ class winhttp_client : public _http_client_communicator cred = p_request_context->m_http_client->client_config().credentials(); p_request_context->m_server_authentication_tried = true; } - else if (dwAuthTarget == WINHTTP_AUTH_TARGET_PROXY && !p_request_context->m_proxy_authentication_tried) + else if (dwAuthTarget == WINHTTP_AUTH_TARGET_PROXY) { - cred = p_request_context->m_http_client->client_config().proxy().credentials(); - p_request_context->m_proxy_authentication_tried = true; + bool is_redirect = false; + try + { + web::uri current_uri(get_request_url(http://github.com/hRequestHandle)); + is_redirect = p_request_context->m_request.absolute_uri().to_string() != current_uri.to_string(); + } + catch (const std::exception&) {} + + // If we have been redirected, then WinHttp needs the proxy credentials again to make the next request leg (which may be on a different server) + if (is_redirect || !p_request_context->m_proxy_authentication_tried) + { + cred = p_request_context->m_http_client->client_config().proxy().credentials(); + p_request_context->m_proxy_authentication_tried = true; + } } // No credentials found so can't resend. From facb5c29ee1cc4ee1433f1e73847816e2c484f20 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 19 Oct 2017 18:25:33 -0700 Subject: [PATCH 140/438] Add android project for vs2017. --- .../vs141.android/cpprest141.android.vcxproj | 138 ++++++++++++++++++ .../src/build/vs141.android/packages.config | 11 ++ cpprestsdk141.sln | 17 ++- 3 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 Release/src/build/vs141.android/cpprest141.android.vcxproj create mode 100644 Release/src/build/vs141.android/packages.config diff --git a/Release/src/build/vs141.android/cpprest141.android.vcxproj b/Release/src/build/vs141.android/cpprest141.android.vcxproj new file mode 100644 index 0000000000..e70534ecfc --- /dev/null +++ b/Release/src/build/vs141.android/cpprest141.android.vcxproj @@ -0,0 +1,138 @@ + + + + + + Debug + ARM + + + Debug + x86 + + + Release + ARM + + + Release + x86 + + + + + + + {AFB49019-965B-4C10-BAFF-C86C16D58010} + Android + Android + 2.0 + cpprest141.android + + + + + StaticLibrary + true + Clang_3_8 + gnustl_static + + + StaticLibrary + true + Clang_3_8 + gnustl_static + + + StaticLibrary + false + Clang_3_8 + gnustl_static + + + StaticLibrary + false + Clang_3_8 + gnustl_static + + + + + + + true + + + true + + + + EnableAllWarnings + $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) + Enabled + c++11 + true + true + -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) + + + + + EnableAllWarnings + $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);%(AdditionalIncludeDirectories) + c++11 + Enabled + true + true + -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) + + + + + EnableAllWarnings + $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) + c++11 + Enabled + true + true + -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) + + + + + EnableAllWarnings + $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) + c++11 + Enabled + true + true + -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) + + + + d + + + $(CppRestBaseFileName)141$(DebugFileSuffix)_android_$(CppRestSDKVersionFileSuffix) + + + true + + + true + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + diff --git a/Release/src/build/vs141.android/packages.config b/Release/src/build/vs141.android/packages.config new file mode 100644 index 0000000000..746b7f61a2 --- /dev/null +++ b/Release/src/build/vs141.android/packages.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/cpprestsdk141.sln b/cpprestsdk141.sln index 1d0d59b04c..f4ed2d2d51 100644 --- a/cpprestsdk141.sln +++ b/cpprestsdk141.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27016.1 +VisualStudioVersion = 15.0.27018.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "android", "Release\src\build\android.vcxitems", "{65951C40-A332-4B54-89C2-7CDAF30D5F66}" EndProject @@ -41,6 +41,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlackJack_Client141", "Rele EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BingRequest141", "Release\samples\BingRequest\BingRequest141\BingRequest141.vcxproj", "{2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprest141.android", "Release\src\build\vs141.android\cpprest141.android.vcxproj", "{AFB49019-965B-4C10-BAFF-C86C16D58010}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution Release\src\build\winrt.vcxitems*{0a9ba181-7876-4b3d-a5e0-ee673fa51c05}*SharedItemsImports = 9 @@ -51,6 +53,8 @@ Global Release\src\build\other.vcxitems*{3d5908f7-7673-4229-bc46-2007a7af9cae}*SharedItemsImports = 9 Release\src\build\common.vcxitems*{594dcb5f-07e3-4084-a2ce-268611fa629f}*SharedItemsImports = 9 Release\src\build\android.vcxitems*{65951c40-a332-4b54-89c2-7cdaf30d5f66}*SharedItemsImports = 9 + Release\src\build\android.vcxitems*{afb49019-965b-4c10-baff-c86c16d58010}*SharedItemsImports = 4 + Release\src\build\common.vcxitems*{afb49019-965b-4c10-baff-c86c16d58010}*SharedItemsImports = 4 Release\src\build\win32.vcxitems*{f40f4804-50f9-4257-8d74-b9cbb19ac4c3}*SharedItemsImports = 9 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -214,6 +218,16 @@ Global {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x64.Build.0 = Release|x64 {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x86.ActiveCfg = Release|Win32 {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x86.Build.0 = Release|Win32 + {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|ARM.ActiveCfg = Debug|ARM + {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|ARM.Build.0 = Debug|ARM + {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|x64.ActiveCfg = Debug|x86 + {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|x86.ActiveCfg = Debug|x86 + {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|x86.Build.0 = Debug|x86 + {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|ARM.ActiveCfg = Release|ARM + {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|ARM.Build.0 = Release|ARM + {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|x64.ActiveCfg = Release|x86 + {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|x86.ActiveCfg = Release|x86 + {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -236,6 +250,7 @@ Global {84350CD1-D406-4A4F-9571-261CA46D77C5} = {EF775754-D70A-4611-A00C-F49F224FD236} {830B6E2F-9224-41D1-B9C7-A51FC78B00C7} = {EF775754-D70A-4611-A00C-F49F224FD236} {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D} = {EF775754-D70A-4611-A00C-F49F224FD236} + {AFB49019-965B-4C10-BAFF-C86C16D58010} = {92944FCF-7E50-41FD-8A99-DD6869F9AEA5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5782CB9E-B335-4D07-A195-717BF4093536} From d310b6d860703fca18aa1843b0f44086cd2456b9 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Fri, 20 Oct 2017 19:49:42 -0700 Subject: [PATCH 141/438] Update iOS configure script --- Build_iOS/configure.sh | 53 ++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/Build_iOS/configure.sh b/Build_iOS/configure.sh index 8c9c9eafd7..8b0599512c 100755 --- a/Build_iOS/configure.sh +++ b/Build_iOS/configure.sh @@ -1,28 +1,41 @@ #!/bin/bash set -e -git clone https://gist.github.com/c629ae4c7168216a9856.git boostoniphone -pushd boostoniphone -git apply ../fix_boost_version.patch -./boost.sh -popd -mv boostoniphone/ios/framework/boost.framework . +if [ ! -e boost.framework ] + then + git clone -n https://github.com/faithfracture/Apple-Boost-BuildScript Apple-Boost-BuildScript + pushd Apple-Boost-BuildScript + git checkout 86f7570fceaef00846cc75f59c61474758fc65cb + BOOST_LIBS="thread chrono filesystem regex system random" ./boost.sh + popd + mv Apple-Boost-BuildScript/build/boost/1.63.0/ios/framework/boost.framework . + mv boost.framework/Versions/A/Headers boost.headers + mkdir -p boost.framework/Versions/A/Headers + mv boost.headers boost.framework/Versions/A/Headers/boost +fi -git clone --depth=1 https://github.com/x2on/OpenSSL-for-iPhone.git -pushd OpenSSL-for-iPhone -./build-libssl.sh -popd -mkdir -p openssl/lib -cp -r OpenSSL-for-iPhone/bin/iPhoneOS8.2-armv7.sdk/include openssl -cp OpenSSL-for-iPhone/include/LICENSE openssl -lipo -create -output openssl/lib/libssl.a OpenSSL-for-iPhone/bin/iPhone*/lib/libssl.a -lipo -create -output openssl/lib/libcrypto.a OpenSSL-for-iPhone/bin/iPhone*/lib/libcrypto.a +if [ ! -e openssl/lib/libcrypto.a ] + then + git clone --depth=1 https://github.com/x2on/OpenSSL-for-iPhone.git + pushd OpenSSL-for-iPhone + ./build-libssl.sh + popd + mkdir -p openssl/lib + cp -r OpenSSL-for-iPhone/bin/iPhoneOS9.2-armv7.sdk/include openssl + cp OpenSSL-for-iPhone/include/LICENSE openssl + lipo -create -output openssl/lib/libssl.a OpenSSL-for-iPhone/bin/iPhone*/lib/libssl.a + lipo -create -output openssl/lib/libcrypto.a OpenSSL-for-iPhone/bin/iPhone*/lib/libcrypto.a +fi -git clone https://github.com/cristeab/ios-cmake.git -pushd ios-cmake -git apply ../fix_ios_cmake_compiler.patch -popd -mkdir build.ios +if [ ! -e ios-cmake/toolchain/iOS.cmake ] + then + git clone https://github.com/cristeab/ios-cmake.git + pushd ios-cmake + git apply ../fix_ios_cmake_compiler.patch + popd +fi + +mkdir -p build.ios pushd build.ios cmake .. -DCMAKE_BUILD_TYPE=Release make From 4375362370309a587f4c39b1fdc8fe2fefe3443a Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 21 Oct 2017 00:50:08 -0700 Subject: [PATCH 142/438] Update readme to include new CMake find_package() scripts --- README.md | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index b0e0d051e9..ae75be9704 100644 --- a/README.md +++ b/README.md @@ -29,26 +29,10 @@ To use from CMake: cmake_minimum_required(VERSION 3.7) project(main) -find_path(CPPREST_INCLUDE cpprest/http_client.h) -find_library(CPPREST_LIB NAMES cpprest_2_9d cpprest_2_9 cpprestd cpprest) -find_package(Boost REQUIRED COMPONENTS random system thread filesystem chrono atomic date_time regex) -find_package(OpenSSL 1.0.0 REQUIRED) +find_package(cpprestsdk REQUIRED) add_executable(main main.cpp) -target_include_directories(main ${CPPREST_INCLUDE}) -target_link_libraries(main - ${CPPREST_LIB} - Boost::boost - Boost::random - Boost::system - Boost::thread - Boost::filesystem - Boost::chrono - Boost::atomic - Boost::date_time - Boost::regex - OpenSSL::SSL -) +target_link_libraries(main PRIVATE cpprestsdk::cpprest) ``` ## What's in the SDK: From 71332b5e18acf6e403da09137f6e8948cb802687 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 21 Oct 2017 00:53:54 -0700 Subject: [PATCH 143/438] Add changelog for v2.10.0 --- changelog.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 changelog.md diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000000..c3db452003 --- /dev/null +++ b/changelog.md @@ -0,0 +1,52 @@ +cpprestsdk (2.10.0) +---------------------- +* Removed VS2013 MSBuild files. Use CMake with the "Visual Studio 12 2013" generator. +* Added VS2017 MSBuild files for convenience. It is highly recommended to use vcpkg or CMake instead to build the product library. +* Added UWP versions of the Windows Store samples for VS2017. +* Updated minimum required cmake version to 3.0. +* Added CMake config-file support to installation. This should be consumed by doing: +```cmake +find_package(cpprestsdk REQUIRED) +target_link_libraries(my_executable PRIVATE cpprestsdk::cpprest) +``` +* Fixed several race conditions and memory leaks in the ASIO `http_client`. +* Fixed process termination bug around certain exceptional cases in all `http_client`s. +* Improved handling of `/Zcwchar_t-` on MSVC. That doesn't make it a good idea. +* Fixed use-after-free in the Windows Desktop `http_client` exposed by VS2017. +* Totally overhaul the CMake buildsystem for much better support of Windows and more shared code between platforms. +* PR#550 adds all remaining official HTTP status codes to `http::status_codes`. +* PR#563 wraps SSL errors on Windows Desktop in `http_exception`s, with more readable descriptions. +* PR#562 and PR#307 fixes building with LibreSSL. +* PR#551 adds convenience wrappers `json::value::has_T_field(T)` for inspecting object values. +* PR#549 fixes a race condition in the ASIO client during header parsing. +* PR#495 fixes a memory leak during proxy autodetection on Windows Desktop. +* PR#496 and PR#500 expand proxy autodetection to also consider Internet Explorer settings on Windows Desktop. +* PR#498 fixes error when handling responses of type NoContent, NotModified, or from 100 to 199. +* PR#398 enables specifying the User Agent used in OAuth2 requests. +* PR#494 improves the BingRequest sample's handling of proxies. +* PR#516 enables certificate revocation checks on Windows Desktop. +* PR#502 improves compatibility with glibc 2.26. +* PR#507 adds `http_request::get_remote_address()` to expose the client's IP address for `http_listener`. +* PR#521 enables use of empty passwords on Windows in `web::credentials`. +* PR#526 and PR#285 improve compatibility with openssl 1.1.0. +* PR#527 fixes a bug in the ASIO `http_client` where the proxy is passed the same credentials as the target host. +* PR#504 makes `uri_builder::to_string()` and `uri_builder::to_uri()` `const`. +* PR#446 adds handling for the host wildchar `+` to the ASIO `http_listener`. +* PR#465 improves compatibility with clang on Linux. +* PR#454 improves compatibility with icc 17.0. +* PR#487 fixes static library builds of `test_runner` on non-Windows platforms. +* PR#415 handles malformed URL requests to the ASIO `http_listener` instead of crashing. +* PR#393 fixes a race condition in the websocketpp `websocket_client`. +* PR#259 fixes several races in the ASIO `http_listener` which result in memory leaks or use after free of the connection objects. +* PR#376 adds `http_client_config::set_nativesessionhandle_options()` which enables customization of the session handle on Windows Desktop. +* PR#365 updates our convenience OpenSSL build scripts for Android to use openssl 1.0.2k. +* PR#336 makes the ASIO `http_client` more consistent with the Windows clients by not appending the port when it is default. This improves compatibility with AWS S3. +* PR#251 dramatically improves UTF8/16 conversions from 6s per 1MB to 3s per 1GB (2000x improvement). +* PR#246 enables TLS 1.1 and 1.2 on Windows 7 and Windows 8. +* PR#308 enables limited IPv6 support to `http_client` and `http_server`, depending on the underlying platform. +* PR#309 fixes a bug in base64 encoding that previously read beyond the input array, causing segfaults/AVs. +* PR#233 adds compression support (deflate and gzip) for Windows Desktop and ASIO `http_client`s based on Zlib. +* PR#218 fixes a memory leak in the UWP `http_client` when processing headers. +* PR#260 fixes inappropriate handling of certain connections errors in the ASIO `http_listener`. + +-- cpprestsdk team SAT, 21 Oct 2017 00:52:00 -0800 From 28919d0e127fc8d5cf57fae2db5d1b92b4eab381 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 21 Oct 2017 01:41:28 -0700 Subject: [PATCH 144/438] Fix issue CMake building for UWP --- Release/CMakeLists.txt | 9 +++++++-- Release/src/CMakeLists.txt | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index a06623bf20..bc1d612ec9 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -69,7 +69,7 @@ elseif(UNIX AND NOT APPLE) # Note: also android set(CPPREST_HTTP_CLIENT_IMPL asio CACHE STRING "Internal use.") set(CPPREST_HTTP_LISTENER_IMPL asio CACHE STRING "Internal use.") elseif(WINDOWS_PHONE OR WINDOWS_STORE) - set(CPPREST_PPLX_IMPL win CACHE STRING "Internal use.") + set(CPPREST_PPLX_IMPL winrt CACHE STRING "Internal use.") set(CPPREST_WEBSOCKETS_IMPL winrt CACHE STRING "Internal use.") set(CPPREST_FILEIO_IMPL winrt CACHE STRING "Internal use.") set(CPPREST_HTTP_CLIENT_IMPL winrt CACHE STRING "Internal use.") @@ -115,7 +115,12 @@ elseif(ANDROID) ) elseif(UNIX) # This includes OSX elseif(WIN32) - add_definitions(-DUNICODE -D_UNICODE -D_WIN32_WINNT=0x0600 -DWIN32 -D_SCL_SECURE_NO_WARNINGS) + add_definitions(-DUNICODE -D_UNICODE -DWIN32 -D_SCL_SECURE_NO_WARNINGS) + if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") + add_definitions(-D_WIN32_WINNT=0x0A00) + else() + add_definitions(-D_WIN32_WINNT=0x0600) + endif() if(NOT BUILD_SHARED_LIBS) # This causes cmake to not link the test libraries separately, but instead hold onto their object files. diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 1c460684ab..070ab41c01 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -80,6 +80,11 @@ elseif(CPPREST_PPLX_IMPL STREQUAL "winpplx") pplx/threadpool.cpp pplx/pplxwin.cpp ) +elseif(CPPREST_PPLX_IMPL STREQUAL "winrt") + list(APPEND SOURCES + pplx/pplxwin.cpp + ) + list(FILTER HEADERS_PPLX EXCLUDE REGEX "threadpool\\.h") endif() # Http client component @@ -186,6 +191,7 @@ if(CPPREST_PPLX_IMPL STREQUAL "apple") target_link_libraries(cpprest PRIVATE ${COREFOUNDATION} ${SECURITY}) elseif(CPPREST_PPLX_IMPL STREQUAL "linux") elseif(CPPREST_PPLX_IMPL STREQUAL "win") +elseif(CPPREST_PPLX_IMPL STREQUAL "winrt") elseif(CPPREST_PPLX_IMPL STREQUAL "winpplx") target_compile_definitions(cpprest PUBLIC -DCPPREST_FORCE_PPLX=1) else() From 5a87137fa62d8358222bb81b5eb49ec1c9b4eda7 Mon Sep 17 00:00:00 2001 From: Adam Duskett Date: Mon, 23 Oct 2017 09:06:12 -0400 Subject: [PATCH 145/438] fix compiling with non-glib Linux c libraries This commit fixes building against uclibc and musl c libraries. - musl requires sys/time.h - musl and uclibc don't define __GLIBC__, and don't include xlocal.h. Instead of adding more define checks, have cmake check for the header and set the define "HAVE_XLOCALE_H", then check for that instead. --- Release/CMakeLists.txt | 2 ++ Release/include/cpprest/asyncrt_utils.h | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index bc1d612ec9..b6ce47d2e2 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -42,6 +42,7 @@ include(cmake/cpprest_find_boost.cmake) include(cmake/cpprest_find_zlib.cmake) include(cmake/cpprest_find_openssl.cmake) include(cmake/cpprest_find_websocketpp.cmake) +include(CheckIncludeFiles) find_package(Threads REQUIRED) if(THREADS_HAVE_PTHREAD_ARG) @@ -56,6 +57,7 @@ if(CPPREST_EXCLUDE_WEBSOCKETS) set(CPPREST_WEBSOCKETS_IMPL none CACHE STRING "Internal use.") endif() +CHECK_INCLUDE_FILES(xlocale.h HAVE_XLOCALE_H) if(APPLE) # Note: also iOS set(CPPREST_PPLX_IMPL apple CACHE STRING "Internal use.") set(CPPREST_WEBSOCKETS_IMPL wspp CACHE STRING "Internal use.") diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index fac70a91a9..064d00f9c2 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -19,17 +19,17 @@ #include #include #include - #include "pplx/pplxtasks.h" #include "cpprest/details/basic_types.h" #if !defined(_WIN32) || (_MSC_VER >= 1700) +#include #include #endif #ifndef _WIN32 #include -#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(__GLIBC__) // CodePlex 269 +#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 Further details: https://sourceware.org/git/?p=glibc.git;a=commit;h=f0be25b6336db7492e47d2e8e72eb8af53b5506d */ From c0e31f075d300014c826c63bdfaed491a43944af Mon Sep 17 00:00:00 2001 From: deeringc Date: Tue, 24 Oct 2017 10:38:14 +0100 Subject: [PATCH 146/438] Add type checks to oauth2 parsing code --- Release/src/http/oauth/oauth2.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Release/src/http/oauth/oauth2.cpp b/Release/src/http/oauth/oauth2.cpp index 09a453835c..e133a65202 100644 --- a/Release/src/http/oauth/oauth2.cpp +++ b/Release/src/http/oauth/oauth2.cpp @@ -149,7 +149,7 @@ oauth2_token oauth2_config::_parse_token_from_json(const json::value& token_json { oauth2_token result; - if (token_json.has_field(oauth2_strings::access_token)) + if (token_json.has_string_field(oauth2_strings::access_token)) { result.set_access_token(token_json.at(oauth2_strings::access_token).as_string()); } @@ -158,7 +158,7 @@ oauth2_token oauth2_config::_parse_token_from_json(const json::value& token_json throw oauth2_exception(U("response json contains no 'access_token': ") + token_json.serialize()); } - if (token_json.has_field(oauth2_strings::token_type)) + if (token_json.has_string_field(oauth2_strings::token_type)) { result.set_token_type(token_json.at(oauth2_strings::token_type).as_string()); } @@ -174,7 +174,7 @@ oauth2_token oauth2_config::_parse_token_from_json(const json::value& token_json throw oauth2_exception(U("only 'token_type=bearer' access tokens are currently supported: ") + token_json.serialize()); } - if (token_json.has_field(oauth2_strings::refresh_token)) + if (token_json.has_string_field(oauth2_strings::refresh_token)) { result.set_refresh_token(token_json.at(oauth2_strings::refresh_token).as_string()); } @@ -205,7 +205,7 @@ oauth2_token oauth2_config::_parse_token_from_json(const json::value& token_json result.set_expires_in(oauth2_token::undefined_expiration); } - if (token_json.has_field(oauth2_strings::scope)) + if (token_json.has_string_field(oauth2_strings::scope)) { // The authorization server may return different scope from the one requested. // This however doesn't necessarily mean the token authorization scope is different. From a7e49f51866b3c743024ec919977356b06eb9bdd Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 31 Oct 2017 05:22:51 -0700 Subject: [PATCH 147/438] Apply fixes from #568 to VS2017 projects. --- .../BingRequest141/BingRequest141.vcxproj | 4 +++- .../BlackJack_Client141.vcxproj | 4 +++- .../BlackJack_Server141.vcxproj | 4 +++- .../BlackJack_UIClient141.vcxproj | 12 +++++++++--- .../CasaLens/CasaLens141/CasaLens141.vcxproj | 4 +++- .../FacebookDemo/FacebookDemo141.vcxproj | 8 ++++---- .../samples/OAuth2Live/OAuth2Live141.vcxproj | 8 ++++---- .../Oauth1Client141/Oauth1Client141.vcxproj | 4 +++- .../Oauth2Client141/Oauth2Client141.vcxproj | 3 ++- .../SearchFile141/SearchFile141.vcxproj | 3 ++- .../WindowsLiveAuth/WindowsLiveAuth141.vcxproj | 2 +- Release/src/android/asm/page.h | 5 +++++ .../vs141.android/cpprest141.android.vcxproj | 18 ++++++++++-------- .../src/build/vs141.uwp/cpprest141.uwp.vcxproj | 6 +++--- Release/src/build/vs141/cpprest141.vcxproj | 9 ++++++++- 15 files changed, 63 insertions(+), 31 deletions(-) create mode 100644 Release/src/android/asm/page.h diff --git a/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj b/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj index 04ca9dee54..b5af27cbca 100644 --- a/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj +++ b/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj @@ -1,4 +1,4 @@ - + @@ -26,6 +26,7 @@ SAK Win32Proj $(VCTargetsPath12) + 10.0.16299.0 @@ -123,6 +124,7 @@ + {1014c621-bc2d-4813-b8c1-6d83ad6f9249} diff --git a/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj b/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj index f06fd04ff8..8770125299 100644 --- a/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj +++ b/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj @@ -1,4 +1,4 @@ - + @@ -27,6 +27,7 @@ SAK SAK $(VCTargetsPath12) + 10.0.16299.0 @@ -141,6 +142,7 @@ + {1014c621-bc2d-4813-b8c1-6d83ad6f9249} diff --git a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj b/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj index 928d64e91c..ff8468da47 100644 --- a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj +++ b/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj @@ -1,4 +1,4 @@ - + @@ -27,6 +27,7 @@ SAK $(VCTargetsPath12) SAK + 10.0.16299.0 @@ -147,6 +148,7 @@ + {1014c621-bc2d-4813-b8c1-6d83ad6f9249} diff --git a/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient141.vcxproj b/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient141.vcxproj index 2479ddea21..9fd3069aa1 100644 --- a/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient141.vcxproj +++ b/Release/samples/BlackJack/BlackJack_UIClient/BlackJack_UIClient141.vcxproj @@ -38,8 +38,8 @@ SAK Windows Store 10.0 - 10.0.10240.0 - 10.0.10240.0 + 10.0.16299.0 + 10.0.16299.0 @@ -107,6 +107,12 @@ WIN32;%(PreprocessorDefinitions) $(CasablancaIncludeDir);%(AdditionalIncludeDirectories) 4100;4267;4450;4453;4702;%(DisableSpecificWarnings) + /Zm150 %(AdditionalOptions) + /Zm150 %(AdditionalOptions) + /Zm150 %(AdditionalOptions) + /Zm150 %(AdditionalOptions) + /Zm150 %(AdditionalOptions) + /Zm150 %(AdditionalOptions) @@ -173,7 +179,7 @@ - {198ED804-2655-4D92-8104-C220E3EA9452} + {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} diff --git a/Release/samples/CasaLens/CasaLens141/CasaLens141.vcxproj b/Release/samples/CasaLens/CasaLens141/CasaLens141.vcxproj index bc93468518..e43ab1b904 100644 --- a/Release/samples/CasaLens/CasaLens141/CasaLens141.vcxproj +++ b/Release/samples/CasaLens/CasaLens141/CasaLens141.vcxproj @@ -1,4 +1,4 @@ - + @@ -26,6 +26,7 @@ SAK Win32Proj $(VCTargetsPath12) + 10.0.16299.0 @@ -140,6 +141,7 @@ + {1014c621-bc2d-4813-b8c1-6d83ad6f9249} diff --git a/Release/samples/FacebookDemo/FacebookDemo141.vcxproj b/Release/samples/FacebookDemo/FacebookDemo141.vcxproj index af5715d233..fb8baf2f63 100644 --- a/Release/samples/FacebookDemo/FacebookDemo141.vcxproj +++ b/Release/samples/FacebookDemo/FacebookDemo141.vcxproj @@ -1,4 +1,4 @@ - + @@ -33,8 +33,8 @@ 14.0 true Windows Store - 10.0.10240.0 - 10.0.10240.0 + 10.0.16299.0 + 10.0.16299.0 10.0 @@ -175,7 +175,7 @@ - {198ed804-2655-4d92-8104-c220e3ea9452} + {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} diff --git a/Release/samples/OAuth2Live/OAuth2Live141.vcxproj b/Release/samples/OAuth2Live/OAuth2Live141.vcxproj index 4607d183a0..07d4d46897 100644 --- a/Release/samples/OAuth2Live/OAuth2Live141.vcxproj +++ b/Release/samples/OAuth2Live/OAuth2Live141.vcxproj @@ -1,4 +1,4 @@ - + @@ -33,8 +33,8 @@ 14.0 true Windows Store - 10.0.10240.0 - 10.0.10240.0 + 10.0.16299.0 + 10.0.16299.0 10.0 @@ -181,7 +181,7 @@ - {198ed804-2655-4d92-8104-c220e3ea9452} + {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} diff --git a/Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj b/Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj index 9dff0e2207..6ff9eeb18a 100644 --- a/Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj +++ b/Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj @@ -1,4 +1,4 @@ - + @@ -35,6 +35,7 @@ SAK SAK $(VCTargetsPath12) + 10.0.16299.0 @@ -198,6 +199,7 @@ + {1014c621-bc2d-4813-b8c1-6d83ad6f9249} diff --git a/Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj b/Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj index a0d3d0fdeb..1ff3cc807d 100644 --- a/Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj +++ b/Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj @@ -1,4 +1,4 @@ - + @@ -35,6 +35,7 @@ SAK SAK $(VCTargetsPath12) + 10.0.16299.0 diff --git a/Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj b/Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj index 7fa2bd5235..4c1d729dcd 100644 --- a/Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj +++ b/Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj @@ -1,4 +1,4 @@ - + @@ -26,6 +26,7 @@ SAK Win32Proj $(VCTargetsPath12) + 10.0.16299.0 diff --git a/Release/samples/WindowsLiveAuth/WindowsLiveAuth141.vcxproj b/Release/samples/WindowsLiveAuth/WindowsLiveAuth141.vcxproj index 3983220d9e..7fec114667 100644 --- a/Release/samples/WindowsLiveAuth/WindowsLiveAuth141.vcxproj +++ b/Release/samples/WindowsLiveAuth/WindowsLiveAuth141.vcxproj @@ -182,7 +182,7 @@ - {198ed804-2655-4d92-8104-c220e3ea9452} + {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} diff --git a/Release/src/android/asm/page.h b/Release/src/android/asm/page.h new file mode 100644 index 0000000000..bd2f6e60c5 --- /dev/null +++ b/Release/src/android/asm/page.h @@ -0,0 +1,5 @@ +#pragma once + +// This file is to fix a break introduced by Android 5 in Boost 1.55. + +// As noted in http://code.google.com/p/android/issues/detail?id=39983, asm/page.h was removed. diff --git a/Release/src/build/vs141.android/cpprest141.android.vcxproj b/Release/src/build/vs141.android/cpprest141.android.vcxproj index e70534ecfc..99a265fa01 100644 --- a/Release/src/build/vs141.android/cpprest141.android.vcxproj +++ b/Release/src/build/vs141.android/cpprest141.android.vcxproj @@ -1,5 +1,5 @@ - - + + @@ -26,8 +26,9 @@ {AFB49019-965B-4C10-BAFF-C86C16D58010} Android Android - 2.0 + 3.0 cpprest141.android + 15.0 @@ -36,6 +37,7 @@ true Clang_3_8 gnustl_static + android-24 StaticLibrary @@ -68,7 +70,7 @@ EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) + $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(CasablancaSrcDir)\android;$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) Enabled c++11 true @@ -79,7 +81,7 @@ EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);%(AdditionalIncludeDirectories) + $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(CasablancaSrcDir)\android;$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);%(AdditionalIncludeDirectories) c++11 Enabled true @@ -90,7 +92,7 @@ EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) + $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(CasablancaSrcDir)\android;$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) c++11 Enabled true @@ -101,7 +103,7 @@ EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) + $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(CasablancaSrcDir)\android;$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) c++11 Enabled true @@ -135,4 +137,4 @@ - + \ No newline at end of file diff --git a/Release/src/build/vs141.uwp/cpprest141.uwp.vcxproj b/Release/src/build/vs141.uwp/cpprest141.uwp.vcxproj index 874315ee1f..f0ee5aae9d 100644 --- a/Release/src/build/vs141.uwp/cpprest141.uwp.vcxproj +++ b/Release/src/build/vs141.uwp/cpprest141.uwp.vcxproj @@ -1,4 +1,4 @@ - + @@ -34,8 +34,8 @@ 14.0 true Windows Store - 10.0.10240.0 - 10.0.10240.0 + 10.0.16299.0 + 10.0.16299.0 10.0 cpprest141.uwp v141 diff --git a/Release/src/build/vs141/cpprest141.vcxproj b/Release/src/build/vs141/cpprest141.vcxproj index 323553b4cc..794a5155ba 100644 --- a/Release/src/build/vs141/cpprest141.vcxproj +++ b/Release/src/build/vs141/cpprest141.vcxproj @@ -1,4 +1,4 @@ - + @@ -13,6 +13,13 @@ false false cpprest141 + 10.0.16299.0 + + + true + true + true + true From 8bd803235f5efa6bcbce480c000f562568f37368 Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Fri, 3 Nov 2017 12:05:35 +0000 Subject: [PATCH 148/438] Resolve gcc "warning: comparison between signed and unsigned integer expressions [-Wsign-compare]" --- Release/include/cpprest/filestream.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Release/include/cpprest/filestream.h b/Release/include/cpprest/filestream.h index 2e60732b05..b8b982556a 100644 --- a/Release/include/cpprest/filestream.h +++ b/Release/include/cpprest/filestream.h @@ -360,7 +360,7 @@ namespace details { size_t written = _putn_fsb(m_info, callback, ptr, count, sizeof(_CharType)); - if ( written != 0 && written != -1 ) + if ( written != 0 && written != size_t(-1) ) { delete callback; written = written/sizeof(_CharType); @@ -572,7 +572,7 @@ namespace details { size_t read = _getn_fsb(m_info, callback, ptr, count, sizeof(_CharType)); - if ( read != 0 && read != -1) + if ( read != 0 && read != size_t(-1) ) { delete callback; pplx::extensibility::scoped_recursive_lock_t lck(m_info->m_lock); From 8ccd130ed2b5447db23157632044f7dbd5e680f5 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sun, 5 Nov 2017 00:45:00 -0700 Subject: [PATCH 149/438] Refactor CMake for better UWP support --- Release/CMakeLists.txt | 13 +- Release/cmake/cpprest_find_boost.cmake | 4 +- Release/src/CMakeLists.txt | 282 ++++++++---------- .../tests/common/TestRunner/CMakeLists.txt | 5 +- .../common/TestRunner/test_module_loader.cpp | 147 +++++---- .../common/TestRunner/test_module_loader.h | 49 +-- .../tests/common/TestRunner/test_runner.cpp | 20 +- .../UnitTestpp/src/TestReporterStdout.cpp | 9 +- .../functional/http/client/CMakeLists.txt | 16 +- .../functional/http/listener/CMakeLists.txt | 13 +- .../functional/http/utilities/CMakeLists.txt | 17 +- Release/tests/functional/json/CMakeLists.txt | 8 +- .../tests/functional/streams/CMakeLists.txt | 16 +- .../functional/streams/stdstream_tests.cpp | 4 +- Release/tests/functional/uri/CMakeLists.txt | 2 +- Release/tests/functional/utils/CMakeLists.txt | 6 +- .../functional/websockets/CMakeLists.txt | 25 +- .../websockets/client/CMakeLists.txt | 15 - 18 files changed, 288 insertions(+), 363 deletions(-) delete mode 100644 Release/tests/functional/websockets/client/CMakeLists.txt diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index bc1d612ec9..218adcbb34 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -125,11 +125,9 @@ elseif(WIN32) if(NOT BUILD_SHARED_LIBS) # This causes cmake to not link the test libraries separately, but instead hold onto their object files. set(TEST_LIBRARY_TARGET_TYPE OBJECT) - set(Casablanca_DEFINITIONS -D_NO_ASYNCRTIMP -D_NO_PPLXIMP CACHE INTERNAL "Definitions for consume casablanca library") - else() - set(Casablanca_DEFINITIONS "" CACHE INTERNAL "Definitions for consume casablanca library") endif() - add_definitions(${Casablanca_DEFINITIONS} -D_WINSOCK_DEPRECATED_NO_WARNINGS) + + add_definitions(-D_WINSOCK_DEPRECATED_NO_WARNINGS) else() message(FATAL_ERROR "-- Unsupported Build Platform.") endif() @@ -198,16 +196,15 @@ function(add_casablanca_test NAME SOURCES_VAR) add_library(${NAME} ${TEST_LIBRARY_TARGET_TYPE} ${${SOURCES_VAR}}) message("-- Added test library ${NAME}") if(TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT") - foreach(_dep httptest_utilities common_utilities unittestpp cpprest) + foreach(_dep cpprest common_utilities unittestpp) target_include_directories(${NAME} PRIVATE $) target_compile_definitions(${NAME} PRIVATE $) endforeach() else() - target_link_libraries(${NAME} - httptest_utilities + target_link_libraries(${NAME} PRIVATE + cpprest common_utilities unittestpp - cpprest ${ANDROID_STL_FLAGS} ) if (BUILD_SHARED_LIBS) diff --git a/Release/cmake/cpprest_find_boost.cmake b/Release/cmake/cpprest_find_boost.cmake index 69b07964c5..298b080aae 100644 --- a/Release/cmake/cpprest_find_boost.cmake +++ b/Release/cmake/cpprest_find_boost.cmake @@ -35,9 +35,9 @@ function(cpprest_find_boost) if(_prev STREQUAL "optimized") list(APPEND _libs "$<$>:${_lib}>") elseif(_prev STREQUAL "debug") - list(APPEND _libs "$<$:${_lib}>") + list(APPEND _libs "$<$:${_lib}>") else() - list(APPEND _libs "${_lib}") + list(APPEND _libs "${_lib}") endif() endif() set(_prev "${_lib}") diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 070ab41c01..e01e075707 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -1,5 +1,9 @@ cmake_policy(SET CMP0022 NEW) +set(CPPREST_VERSION_MAJOR 2) +set(CPPREST_VERSION_MINOR 10) +set(CPPREST_VERSION_REVISION 0) + file(GLOB HEADERS_CPPREST "../include/cpprest/*.h" "../include/cpprest/*.hpp" "../include/cpprest/*.dat") file(GLOB HEADERS_PPLX "../include/pplx/*.h" "../include/pplx/*.hpp") file(GLOB HEADERS_DETAILS "../include/cpprest/details/*.h" "../include/cpprest/details/*.hpp" "../include/cpprest/details/*.dat" "../include/pplx/*.hpp" "../include/pplx/*.dat") @@ -7,6 +11,7 @@ source_group("Header Files\\cpprest" FILES ${HEADERS_CPPREST}) source_group("Header Files\\pplx" FILES ${HEADERS_PPLX}) source_group("Header Files\\cpprest\\details" FILES ${HEADERS_DETAILS}) +list(FILTER HEADERS_PPLX EXCLUDE REGEX "threadpool\\.h") set(SOURCES ${HEADERS_CPPREST} ${HEADERS_PPLX} @@ -37,97 +42,7 @@ set(SOURCES utilities/web_utilities.cpp ) -## Sub-component sources -# Websockets component -if(CPPREST_WEBSOCKETS_IMPL STREQUAL "none") -elseif(CPPREST_WEBSOCKETS_IMPL STREQUAL "winrt") - list(APPEND SOURCES - websockets/client/ws_msg.cpp - websockets/client/ws_client.cpp - websockets/client/ws_client_winrt.cpp - websockets/client/ws_client_impl.h - ) -elseif(CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") - list(APPEND SOURCES - websockets/client/ws_msg.cpp - websockets/client/ws_client.cpp - websockets/client/ws_client_wspp.cpp - websockets/client/ws_client_impl.h - ) -endif() - -# Compression component -# No sources to add - -# PPLX component -if(CPPREST_PPLX_IMPL STREQUAL "apple") - list(APPEND SOURCES - pplx/threadpool.cpp - pplx/pplxapple.cpp - ) -elseif(CPPREST_PPLX_IMPL STREQUAL "linux") - list(APPEND SOURCES - pplx/threadpool.cpp - pplx/pplxlinux.cpp - ) -elseif(CPPREST_PPLX_IMPL STREQUAL "win") - list(APPEND SOURCES - pplx/threadpool.cpp - pplx/pplxwin.cpp - ) -elseif(CPPREST_PPLX_IMPL STREQUAL "winpplx") - list(APPEND SOURCES - pplx/threadpool.cpp - pplx/pplxwin.cpp - ) -elseif(CPPREST_PPLX_IMPL STREQUAL "winrt") - list(APPEND SOURCES - pplx/pplxwin.cpp - ) - list(FILTER HEADERS_PPLX EXCLUDE REGEX "threadpool\\.h") -endif() - -# Http client component -if(CPPREST_HTTP_CLIENT_IMPL STREQUAL "asio") - list(APPEND SOURCES http/client/http_client_asio.cpp) -elseif(CPPREST_HTTP_CLIENT_IMPL STREQUAL "winhttp") - list(APPEND SOURCES http/client/http_client_winhttp.cpp) -elseif(CPPREST_HTTP_CLIENT_IMPL STREQUAL "winrt") - list(APPEND SOURCES http/client/http_client_winrt.cpp) -endif() - -# fileio streams component -if(CPPREST_FILEIO_IMPL STREQUAL "win32") - list(APPEND SOURCES streams/fileio_win32.cpp) -elseif(CPPREST_FILEIO_IMPL STREQUAL "winrt") - list(APPEND SOURCES streams/fileio_winrt.cpp) -elseif(CPPREST_FILEIO_IMPL STREQUAL "posix") - list(APPEND SOURCES streams/fileio_posix.cpp) -endif() - -# http listener component -if(CPPREST_HTTP_LISTENER_IMPL STREQUAL "asio") - list(APPEND SOURCES http/listener/http_server_asio.cpp) -elseif(CPPREST_HTTP_LISTENER_IMPL STREQUAL "httpsys") - list(APPEND SOURCES - http/listener/http_server_httpsys.cpp - http/listener/http_server_httpsys.h) -endif() - -if(MSVC) - set_source_files_properties(pch/stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") - - if (NOT ${CMAKE_GENERATOR} MATCHES "Visual Studio .*") - set_property(SOURCE pch/stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") - set_property(SOURCE ${SOURCES} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") - endif() - - add_library(cpprest ${SOURCES} pch/stdafx.cpp) - target_compile_options(cpprest PRIVATE /Yustdafx.h /Zm200) -else() - add_library(cpprest ${SOURCES}) -endif() - +add_library(cpprest ${SOURCES}) target_include_directories(cpprest PUBLIC $ $ @@ -135,128 +50,170 @@ target_include_directories(cpprest pch ) -if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") - if(WERROR) - target_compile_options(cpprest PRIVATE -Werror) - endif() - target_compile_options(cpprest PRIVATE -pedantic) -elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - if(WERROR) - target_compile_options(cpprest PRIVATE /WX) - endif() -endif() - -if (BUILD_SHARED_LIBS AND WIN32) - target_compile_definitions(cpprest PRIVATE -D_ASYNCRT_EXPORT -D_PPLX_EXPORT -D_USRDLL) -endif() - -target_compile_options(cpprest PRIVATE ${WARNINGS}) - -set(CPPREST_USES_BOOST OFF) -set(CPPREST_USES_OPENSSL OFF) -set(CPPREST_USES_ZLIB OFF) -set(CPPREST_USES_WEBSOCKETPP OFF) - -if (WIN32 AND NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) - target_link_libraries(cpprest PRIVATE - bcrypt.lib - crypt32.lib - ) -endif() - +## Sub-components # Websockets component if(CPPREST_WEBSOCKETS_IMPL STREQUAL "none") target_compile_definitions(cpprest PUBLIC -DCPPREST_EXCLUDE_WEBSOCKETS=1) elseif(CPPREST_WEBSOCKETS_IMPL STREQUAL "winrt") + target_sources(cpprest PRIVATE + websockets/client/ws_msg.cpp + websockets/client/ws_client.cpp + websockets/client/ws_client_impl.h + websockets/client/ws_client_winrt.cpp + ) elseif(CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") - set(CPPREST_USES_WEBSOCKETPP ON) - set(CPPREST_USES_BOOST ON) - set(CPPREST_USES_OPENSSL ON) - set(CPPREST_USES_ZLIB ON) + target_sources(cpprest PRIVATE + websockets/client/ws_msg.cpp + websockets/client/ws_client.cpp + websockets/client/ws_client_impl.h + websockets/client/ws_client_wspp.cpp + ) + cpprest_find_websocketpp() + target_link_libraries(cpprest PRIVATE cpprestsdk_websocketpp_internal) else() message(FATAL_ERROR "Invalid implementation") endif() # Compression component if(CPPREST_EXCLUDE_COMPRESSION) - target_compile_definitions(cpprest PUBLIC -DCPPREST_EXCLUDE_COMPRESSION=1) + target_compile_definitions(cpprest PRIVATE -DCPPREST_EXCLUDE_COMPRESSION=1) else() - set(CPPREST_USES_ZLIB ON) + cpprest_find_zlib() + target_link_libraries(cpprest PRIVATE cpprestsdk_zlib_internal) endif() # PPLX component if(CPPREST_PPLX_IMPL STREQUAL "apple") find_library(COREFOUNDATION CoreFoundation "/") find_library(SECURITY Security "/") - target_link_libraries(cpprest PRIVATE ${COREFOUNDATION} ${SECURITY}) + target_link_libraries(cpprest PUBLIC ${COREFOUNDATION} ${SECURITY}) + target_sources(cpprest PRIVATE pplx/pplxapple.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) + if(CPPREST_INSTALL_HEADERS) + install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) + endif() elseif(CPPREST_PPLX_IMPL STREQUAL "linux") + target_sources(cpprest PRIVATE pplx/pplxlinux.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) + if(CPPREST_INSTALL_HEADERS) + install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) + endif() elseif(CPPREST_PPLX_IMPL STREQUAL "win") -elseif(CPPREST_PPLX_IMPL STREQUAL "winrt") + target_sources(cpprest PRIVATE pplx/pplxwin.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) + if(CPPREST_INSTALL_HEADERS) + install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) + endif() elseif(CPPREST_PPLX_IMPL STREQUAL "winpplx") target_compile_definitions(cpprest PUBLIC -DCPPREST_FORCE_PPLX=1) + target_sources(cpprest PRIVATE pplx/pplxwin.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) + if(CPPREST_INSTALL_HEADERS) + install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) + endif() +elseif(CPPREST_PPLX_IMPL STREQUAL "winrt") + target_sources(cpprest PRIVATE pplx/pplxwin.cpp) else() message(FATAL_ERROR "Invalid implementation") endif() # Http client component if(CPPREST_HTTP_CLIENT_IMPL STREQUAL "asio") - set(CPPREST_USES_BOOST ON) - set(CPPREST_USES_OPENSSL ON) + cpprest_find_boost() + cpprest_find_openssl() target_compile_definitions(cpprest PUBLIC -DCPPREST_FORCE_HTTP_CLIENT_ASIO) + target_sources(cpprest PRIVATE http/client/http_client_asio.cpp) + target_link_libraries(cpprest PUBLIC cpprestsdk_boost_internal cpprestsdk_openssl_internal) elseif(CPPREST_HTTP_CLIENT_IMPL STREQUAL "winhttp") target_link_libraries(cpprest PRIVATE httpapi.lib Winhttp.lib ) + target_sources(cpprest PRIVATE http/client/http_client_winhttp.cpp) elseif(CPPREST_HTTP_CLIENT_IMPL STREQUAL "winrt") + target_sources(cpprest PRIVATE http/client/http_client_winrt.cpp) else() message(FATAL_ERROR "Invalid implementation") endif() # fileio streams component if(CPPREST_FILEIO_IMPL STREQUAL "win32") + target_sources(cpprest PRIVATE streams/fileio_win32.cpp) elseif(CPPREST_FILEIO_IMPL STREQUAL "winrt") + target_sources(cpprest PRIVATE streams/fileio_winrt.cpp) elseif(CPPREST_FILEIO_IMPL STREQUAL "posix") + target_sources(cpprest PRIVATE streams/fileio_posix.cpp) else() message(FATAL_ERROR "Invalid implementation") endif() # http listener component if(CPPREST_HTTP_LISTENER_IMPL STREQUAL "asio") - set(CPPREST_USES_BOOST ON) - set(CPPREST_USES_OPENSSL ON) + cpprest_find_boost() + cpprest_find_openssl() target_compile_definitions(cpprest PUBLIC -DCPPREST_FORCE_HTTP_LISTENER_ASIO) + target_sources(cpprest PRIVATE http/listener/http_server_asio.cpp) + target_link_libraries(cpprest PUBLIC cpprestsdk_boost_internal cpprestsdk_openssl_internal) elseif(CPPREST_HTTP_LISTENER_IMPL STREQUAL "httpsys") + target_sources(cpprest PRIVATE + http/listener/http_server_httpsys.cpp + http/listener/http_server_httpsys.h + ) elseif(CPPREST_HTTP_LISTENER_IMPL STREQUAL "none") else() message(FATAL_ERROR "Invalid implementation") endif() -# Add any libraries that were used. -if(CPPREST_USES_WEBSOCKETPP) - cpprest_find_websocketpp() - target_link_libraries(cpprest PRIVATE cpprestsdk_websocketpp_internal) -endif() -if(CPPREST_USES_BOOST) - cpprest_find_boost() - target_link_libraries(cpprest PUBLIC cpprestsdk_boost_internal) -endif() -if(CPPREST_USES_OPENSSL) - cpprest_find_openssl() - target_link_libraries(cpprest PUBLIC cpprestsdk_openssl_internal) +if(MSVC) + get_target_property(_srcs cpprest SOURCES) + + set_source_files_properties(pch/stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") + list(FILTER _srcs EXCLUDE REGEX "pch/stdafx\\.cpp$") + + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") + set_property(SOURCE pch/stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") + set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") + endif() + + target_sources(cpprest PRIVATE pch/stdafx.cpp) + target_compile_options(cpprest PRIVATE /Yustdafx.h /Zm200) endif() -if(CPPREST_USES_ZLIB) - cpprest_find_zlib() - target_link_libraries(cpprest PRIVATE cpprestsdk_zlib_internal) + +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") + if(WERROR) + target_compile_options(cpprest PRIVATE -Werror) + endif() + target_compile_options(cpprest PRIVATE -pedantic ${WARNINGS}) +elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + if(WERROR) + target_compile_options(cpprest PRIVATE /WX ${WARNINGS}) + endif() +else() + message(FATAL_ERROR "Unknown compiler") endif() -if(ANDROID) + +if(WIN32) + if (BUILD_SHARED_LIBS) + target_compile_definitions(cpprest PRIVATE -D_ASYNCRT_EXPORT -D_PPLX_EXPORT -D_USRDLL) + else() + target_compile_definitions(cpprest INTERFACE -D_NO_ASYNCRTIMP -D_NO_PPLXIMP) + endif() +elseif(ANDROID) target_link_libraries(cpprest PRIVATE ${ANDROID_STL_FLAGS}) endif() -# Portions specific to cpprest binary versioning. -set (CPPREST_VERSION_MAJOR 2) -set (CPPREST_VERSION_MINOR 10) -set (CPPREST_VERSION_REVISION 0) +if (WIN32 AND NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) + target_link_libraries(cpprest PRIVATE + bcrypt.lib + crypt32.lib + ) +elseif(WINDOWS_STORE) + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") + target_compile_definitions(cpprest PRIVATE -DWINAPI_FAMILY=WINAPI_FAMILY_PC_APP) + get_target_property(LINK_FLAGS cpprest LINK_FLAGS) + if(NOT LINK_FLAGS) + set(LINK_FLAGS "") + endif() + set(LINK_FLAGS "${LINK_FLAGS} /APPCONTAINER") + set_target_properties(cpprest PROPERTIES LINK_FLAGS "${LINK_FLAGS}") + endif() +endif() if(WIN32) set_target_properties(cpprest PROPERTIES @@ -269,16 +226,29 @@ else() SOVERSION ${CPPREST_VERSION_MAJOR}.${CPPREST_VERSION_MINOR}) endif() +if(CPPREST_INSTALL_HEADERS) + install(FILES ${HEADERS_CPPREST} DESTINATION include/cpprest) + install(FILES ${HEADERS_PPLX} DESTINATION include/pplx) + install(FILES ${HEADERS_DETAILS} DESTINATION include/cpprest/details) +endif() + if(CPPREST_INSTALL) + set(CPPREST_USES_BOOST OFF) + set(CPPREST_USES_ZLIB OFF) + set(CPPREST_USES_OPENSSL OFF) + set(CPPREST_TARGETS cpprest) if(TARGET cpprestsdk_boost_internal) list(APPEND CPPREST_TARGETS cpprestsdk_boost_internal) + set(CPPREST_USES_BOOST ON) endif() if(TARGET cpprestsdk_zlib_internal) list(APPEND CPPREST_TARGETS cpprestsdk_zlib_internal) + set(CPPREST_USES_ZLIB ON) endif() if(TARGET cpprestsdk_openssl_internal) list(APPEND CPPREST_TARGETS cpprestsdk_openssl_internal) + set(CPPREST_USES_OPENSSL ON) endif() if(TARGET cpprestsdk_websocketpp_internal) list(APPEND CPPREST_TARGETS cpprestsdk_websocketpp_internal) @@ -291,12 +261,6 @@ if(CPPREST_INSTALL) ARCHIVE DESTINATION lib ) - if(CPPREST_INSTALL_HEADERS) - install(FILES ${HEADERS_CPPREST} DESTINATION include/cpprest) - install(FILES ${HEADERS_PPLX} DESTINATION include/pplx) - install(FILES ${HEADERS_DETAILS} DESTINATION include/cpprest/details) - endif() - configure_file(../cmake/cpprestsdk-config.in.cmake "${CMAKE_CURRENT_BINARY_DIR}/cpprestsdk-config.cmake" @ONLY) install( @@ -309,4 +273,4 @@ if(CPPREST_INSTALL) NAMESPACE cpprestsdk:: DESTINATION ${CPPREST_EXPORT_DIR} ) -endif() \ No newline at end of file +endif() diff --git a/Release/tests/common/TestRunner/CMakeLists.txt b/Release/tests/common/TestRunner/CMakeLists.txt index ec74598dee..59b720d24c 100644 --- a/Release/tests/common/TestRunner/CMakeLists.txt +++ b/Release/tests/common/TestRunner/CMakeLists.txt @@ -9,7 +9,7 @@ endif() add_executable(test_runner test_runner.cpp test_module_loader.cpp) target_link_libraries(test_runner PRIVATE unittestpp ${CMAKE_DL_LIBS}) -if(BUILD_SHARED_LIBS) +if(BUILD_SHARED_LIBS AND NOT TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT") elseif(APPLE) target_link_libraries(test_runner PRIVATE -Wl,-force_load httpclient_test @@ -51,6 +51,9 @@ else() httptest_utilities cpprest ) + if(TARGET websockettest_utilities) + target_link_libraries(test_runner PRIVATE websockettest_utilities) + endif() if(CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") cpprest_find_websocketpp() target_link_libraries(test_runner PRIVATE cpprestsdk_websocketpp_internal) diff --git a/Release/tests/common/TestRunner/test_module_loader.cpp b/Release/tests/common/TestRunner/test_module_loader.cpp index 6f4d9f79e7..65968e7a0d 100644 --- a/Release/tests/common/TestRunner/test_module_loader.cpp +++ b/Release/tests/common/TestRunner/test_module_loader.cpp @@ -6,72 +6,24 @@ */ #ifdef WIN32 #include +#else +#include "dlfcn.h" +#include #endif #include "test_module_loader.h" #include -#ifdef WIN32 - -// Windows module -class windows_module : public test_module +class test_module { public: - windows_module(const std::string &dllName) : test_module(dllName), m_hModule(nullptr) {} + test_module(const std::string& dllName) : m_dllName(dllName), m_handle(nullptr) {} GetTestsFunc get_test_list() { - return (GetTestsFunc)GetProcAddress(m_hModule, "GetTestList"); - } - -protected: - - virtual unsigned long load_impl() - { - // Make sure ends in .dll - if(*(m_dllName.end() - 1) != 'l' - || *(m_dllName.end() - 2) != 'l' - || *(m_dllName.end() - 3) != 'd' - || *(m_dllName.end() - 4) != '.') - { - return (unsigned long)-1; - } - m_hModule = LoadLibraryA(m_dllName.c_str()); - if(m_hModule == nullptr) - { - return GetLastError(); - } - return 0; - } - - virtual unsigned long unload_impl() - { - if(!FreeLibrary(m_hModule)) - { - return GetLastError(); - } - return 0; - } - - HMODULE m_hModule; - -private: - windows_module(const windows_module &); - windows_module & operator=(const windows_module &); - -}; - +#if defined(_WIN32) + return (GetTestsFunc)GetProcAddress(m_handle, "GetTestList"); #else -#include "dlfcn.h" -#include - -class linux_module : public test_module -{ -public: - linux_module(const std::string &soName) : test_module(soName), m_handle(nullptr) {} - - GetTestsFunc get_test_list() - { auto ptr = dlsym(m_handle, "GetTestList"); if (ptr == nullptr) { @@ -81,44 +33,87 @@ class linux_module : public test_module #endif std::endl; } - return (GetTestsFunc)ptr; + return (GetTestsFunc)ptr; +#endif } -protected: - - virtual unsigned long load_impl() + unsigned long load() { + if (m_handle == nullptr) + { +#if defined(_WIN32) + // Make sure ends in .dll + if (*(m_dllName.end() - 1) != 'l' + || *(m_dllName.end() - 2) != 'l' + || *(m_dllName.end() - 3) != 'd' + || *(m_dllName.end() - 4) != '.') + { + return (unsigned long)-1; + } + m_handle = LoadLibraryA(m_dllName.c_str()); + if (m_handle == nullptr) + { + return GetLastError(); + } + return 0; +#else #ifdef __APPLE__ - auto exe_directory = getcwd(nullptr, 0); - auto path = std::string(exe_directory) + "/" + m_dllName; - free(exe_directory); + auto exe_directory = getcwd(nullptr, 0); + auto path = std::string(exe_directory) + "/" + m_dllName; + free(exe_directory); #else - auto path = boost::filesystem::initial_path().string() + "/" + m_dllName; + auto path = boost::filesystem::initial_path().string() + "/" + m_dllName; #endif - m_handle = dlopen(path.c_str(), RTLD_LAZY|RTLD_GLOBAL); - if (m_handle == nullptr) - { - std::cerr << std::string(dlerror()) << std::endl; - return -1; + m_handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL); + if (m_handle == nullptr) + { + std::cerr << std::string(dlerror()) << std::endl; + return -1; + } + return 0; +#endif } return 0; } - virtual unsigned long unload_impl() + unsigned long unload() { - if (dlclose(m_handle) != 0) + if (m_handle != nullptr) { - std::cerr << std::string(dlerror()) << std::endl; - return -1; +#if defined(_WIN32) + if (!FreeLibrary(m_handle)) + { + return GetLastError(); + } + m_handle = nullptr; + return 0; +#else + if (dlclose(m_handle) != 0) + { + std::cerr << std::string(dlerror()) << std::endl; + return -1; + } + m_handle = nullptr; + return 0; +#endif } return 0; } +private: + const std::string m_dllName; + +#if defined(_WIN32) + HMODULE m_handle; +#else void* m_handle; -}; #endif + test_module(const test_module &) = delete; + test_module & operator=(const test_module &) = delete; +}; + test_module_loader::test_module_loader() { } @@ -141,11 +136,7 @@ unsigned long test_module_loader::load(const std::string &dllName) } test_module *pModule; -#ifdef WIN32 - pModule = new windows_module(dllName); -#else - pModule = new linux_module(dllName); -#endif + pModule = new test_module(dllName); // Load dll. const unsigned long error_code = pModule->load(); diff --git a/Release/tests/common/TestRunner/test_module_loader.h b/Release/tests/common/TestRunner/test_module_loader.h index cd2389f829..01d90ba4c7 100644 --- a/Release/tests/common/TestRunner/test_module_loader.h +++ b/Release/tests/common/TestRunner/test_module_loader.h @@ -15,51 +15,7 @@ typedef UnitTest::TestList & (__cdecl *GetTestsFunc)(); // Interface to implement on each platform to be be able to load/unload and call global functions. -class test_module -{ -public: - test_module(const std::string &dllName) : m_dllName(dllName), m_loaded(false) {} - virtual ~test_module() {} - - unsigned long load() - { - if(!m_loaded) - { - m_loaded = true; - unsigned long error_code = load_impl(); - if(error_code != 0) - { - m_loaded = false; - } - return error_code; - } - return 0; - } - - virtual GetTestsFunc get_test_list() = 0; - - unsigned long unload() - { - if(m_loaded) - { - m_loaded = false; - return unload_impl(); - } - return 0; - } - -protected: - - virtual unsigned long load_impl() = 0; - virtual unsigned long unload_impl() = 0; - - bool m_loaded; - const std::string m_dllName; - -private: - test_module(const test_module &); - test_module & operator=(const test_module &); -}; +class test_module; // Handles organizing all test binaries and using the correct module loader. class test_module_loader @@ -75,6 +31,9 @@ class test_module_loader UnitTest::TestList& get_test_list(const std::string &dllName); private: + test_module_loader(const test_module_loader &) = delete; + test_module_loader & operator=(const test_module_loader &) = delete; + std::map m_modules; }; diff --git a/Release/tests/common/TestRunner/test_runner.cpp b/Release/tests/common/TestRunner/test_runner.cpp index 263eb82c91..bb5160d4d9 100644 --- a/Release/tests/common/TestRunner/test_runner.cpp +++ b/Release/tests/common/TestRunner/test_runner.cpp @@ -336,7 +336,8 @@ static void handle_list_option(bool listProperties, const UnitTest::TestList &te static void ChangeConsoleTextColorToRed() { -#ifdef _WIN32 +#if defined(__cplusplus_winrt) +#elif defined(_WIN32) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x0004 | 0x0008); #else std::cout << "\033[1;31m"; @@ -345,7 +346,8 @@ static void ChangeConsoleTextColorToRed() static void ChangeConsoleTextColorToGreen() { -#ifdef _WIN32 +#if defined(__cplusplus_winrt) +#elif defined(_WIN32) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x0002 | 0x0008); #else std::cout << "\033[1;32m"; @@ -354,7 +356,8 @@ static void ChangeConsoleTextColorToGreen() static void ChangeConsoleTextColorToGrey() { -#ifdef _WIN32 +#if defined(__cplusplus_winrt) +#elif defined(_WIN32) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN); #else std::cout << "\033[0m"; @@ -494,9 +497,15 @@ void run_all_tests(UnitTest::TestRunner& testRunner, testlist_t& testlists) } } +#if defined(__cplusplus_winrt) +#include "ROApi.h" +#endif + int main(int argc, char* argv[]) { -#ifdef _WIN32 +#if defined(__cplusplus_winrt) + Windows::Foundation::Initialize(RO_INIT_MULTITHREADED); +#elif defined(_WIN32) // Add standard error as output as well. _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_WNDW | _CRTDBG_MODE_DEBUG); _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); @@ -623,7 +632,8 @@ int main(int argc, char* argv[]) << "Took " << elapsedTime << "ms" << std::endl; } -#ifdef _WIN32 +#if defined(__cplusplus_winrt) +#elif defined(_WIN32) if(hComBase != nullptr) { typedef void (WINAPI *RoUnInit)(); diff --git a/Release/tests/common/UnitTestpp/src/TestReporterStdout.cpp b/Release/tests/common/UnitTestpp/src/TestReporterStdout.cpp index ee0b154224..a6e9b25b08 100644 --- a/Release/tests/common/UnitTestpp/src/TestReporterStdout.cpp +++ b/Release/tests/common/UnitTestpp/src/TestReporterStdout.cpp @@ -68,7 +68,8 @@ static void PrintfWrapper(const char* format, ...) static void ChangeConsoleTextColorToRed() { -#ifdef _WIN32 +#if defined(__cplusplus_winrt) +#elif defined(_WIN32) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x0004 | 0x0008); #else std::cout << "\033[1;31m"; @@ -77,7 +78,8 @@ static void ChangeConsoleTextColorToRed() static void ChangeConsoleTextColorToGreen() { -#ifdef _WIN32 +#if defined(__cplusplus_winrt) +#elif defined(_WIN32) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x0002 | 0x0008); #else std::cout << "\033[1;32m"; @@ -86,7 +88,8 @@ static void ChangeConsoleTextColorToGreen() static void ChangeConsoleTextColorToGrey() { -#ifdef _WIN32 +#if defined(__cplusplus_winrt) +#elif defined(_WIN32) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN); #else std::cout << "\033[0m"; diff --git a/Release/tests/functional/http/client/CMakeLists.txt b/Release/tests/functional/http/client/CMakeLists.txt index 93bc5475bb..60804e1742 100644 --- a/Release/tests/functional/http/client/CMakeLists.txt +++ b/Release/tests/functional/http/client/CMakeLists.txt @@ -1,9 +1,3 @@ -include_directories( - ../utilities/include - ../utilities/testlistener/include - ${Casablanca_INCLUDE_DIRS} -) - set(SOURCES authentication_tests.cpp building_request_tests.cpp @@ -30,8 +24,14 @@ set(SOURCES stdafx.cpp ) +add_casablanca_test(httpclient_test SOURCES) +if(TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT") + target_include_directories(httpclient_test PRIVATE ../utilities/include) +else() + target_link_libraries(httpclient_test PRIVATE httptest_utilities) +endif() + if(NOT WIN32) cpprest_find_boost() - link_libraries(cpprestsdk_boost_internal) + target_link_libraries(httpclient_test PRIVATE cpprestsdk_boost_internal) endif() -add_casablanca_test(httpclient_test SOURCES) diff --git a/Release/tests/functional/http/listener/CMakeLists.txt b/Release/tests/functional/http/listener/CMakeLists.txt index 270b89de25..33be6fb354 100644 --- a/Release/tests/functional/http/listener/CMakeLists.txt +++ b/Release/tests/functional/http/listener/CMakeLists.txt @@ -1,6 +1,4 @@ -if (NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) - include_directories (../utilities/include) - +if(NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) set (SOURCES building_response_tests.cpp connections_and_errors.cpp @@ -17,6 +15,11 @@ if (NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) to_string_tests.cpp stdafx.cpp ) - + add_casablanca_test(httplistener_test SOURCES) -endif () \ No newline at end of file + if(TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT") + target_include_directories(httplistener_test PRIVATE ../utilities/include) + else() + target_link_libraries(httplistener_test PRIVATE httptest_utilities) + endif() +endif() diff --git a/Release/tests/functional/http/utilities/CMakeLists.txt b/Release/tests/functional/http/utilities/CMakeLists.txt index e93e2c4e91..3edf3296e5 100644 --- a/Release/tests/functional/http/utilities/CMakeLists.txt +++ b/Release/tests/functional/http/utilities/CMakeLists.txt @@ -1,9 +1,3 @@ -include_directories(include) - -if(WIN32) - add_definitions(-DHTTPTESTUTILITY_EXPORTS) -endif() - set(SOURCES http_asserts.cpp test_http_client.cpp @@ -12,8 +6,15 @@ set(SOURCES ) add_library(httptest_utilities ${SOURCES}) -target_link_libraries(httptest_utilities +if(WIN32) + target_compile_definitions(httptest_utilities PRIVATE -DHTTPTESTUTILITY_EXPORTS) +endif() +target_include_directories(httptest_utilities PUBLIC include) +target_link_libraries(httptest_utilities PUBLIC + cpprest unittestpp common_utilities - cpprest ) +if(WINDOWS_STORE) + target_compile_options(httptest_utilities PRIVATE /DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP) +endif() diff --git a/Release/tests/functional/json/CMakeLists.txt b/Release/tests/functional/json/CMakeLists.txt index 2972052f01..379a6bd4bf 100644 --- a/Release/tests/functional/json/CMakeLists.txt +++ b/Release/tests/functional/json/CMakeLists.txt @@ -1,4 +1,4 @@ -set (SOURCES +set(SOURCES construction_tests.cpp negative_parsing_tests.cpp parsing_tests.cpp @@ -7,12 +7,12 @@ set (SOURCES json_numbers_tests.cpp stdafx.cpp ) -if (NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) +if(NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) list(APPEND SOURCES fuzz_tests.cpp) endif() +add_casablanca_test(json_test SOURCES) if(UNIX AND NOT APPLE) cpprest_find_boost() - link_libraries(cpprestsdk_boost_internal) + target_link_libraries(json_test PRIVATE cpprestsdk_boost_internal) endif() -add_casablanca_test(json_test SOURCES) diff --git a/Release/tests/functional/streams/CMakeLists.txt b/Release/tests/functional/streams/CMakeLists.txt index 14cb97f2ce..af45beffca 100644 --- a/Release/tests/functional/streams/CMakeLists.txt +++ b/Release/tests/functional/streams/CMakeLists.txt @@ -6,17 +6,17 @@ set(SOURCES stdstream_tests.cpp stdafx.cpp ) -if (NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) +if(WINDOWS_STORE OR WINDOWS_PHONE) + list(APPEND SOURCES winrt_interop_tests.cpp) +else() list(APPEND SOURCES fuzz_tests.cpp) - if (WIN32) + if(WIN32) list(APPEND SOURCES CppSparseFile.cpp) - endif () -else () - list(APPEND SOURCES winrt_interop_tests.cpp) -endif () + endif() +endif() +add_casablanca_test(streams_test SOURCES) if(NOT WIN32 OR CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") cpprest_find_boost() - link_libraries(cpprestsdk_boost_internal) + target_link_libraries(streams_test PRIVATE cpprestsdk_boost_internal) endif() -add_casablanca_test(streams_test SOURCES) diff --git a/Release/tests/functional/streams/stdstream_tests.cpp b/Release/tests/functional/streams/stdstream_tests.cpp index bd24c2bbe7..a8fde13499 100644 --- a/Release/tests/functional/streams/stdstream_tests.cpp +++ b/Release/tests/functional/streams/stdstream_tests.cpp @@ -14,7 +14,7 @@ #include "cpprest/filestream.h" #include "cpprest/producerconsumerstream.h" -#if !defined(_WIN32) || !defined(CPPREST_EXCLUDE_WEBSOCKETS) +#if (!defined(_WIN32) || !defined(CPPREST_EXCLUDE_WEBSOCKETS)) && !defined(__cplusplus_winrt) #include #endif @@ -777,7 +777,7 @@ TEST(sync_on_async_close_with_exception) } } -#if !defined(_WIN32) || !defined(CPPREST_EXCLUDE_WEBSOCKETS) +#if (!defined(_WIN32) || !defined(CPPREST_EXCLUDE_WEBSOCKETS)) && !defined(__cplusplus_winrt) TEST(ostream_full_throw_exception) { char tgt_buffer[5]; diff --git a/Release/tests/functional/uri/CMakeLists.txt b/Release/tests/functional/uri/CMakeLists.txt index 19c2052817..f869e24d18 100644 --- a/Release/tests/functional/uri/CMakeLists.txt +++ b/Release/tests/functional/uri/CMakeLists.txt @@ -11,4 +11,4 @@ set(SOURCES stdafx.cpp ) -add_casablanca_test(${LIB}uri_test SOURCES) +add_casablanca_test(uri_test SOURCES) diff --git a/Release/tests/functional/utils/CMakeLists.txt b/Release/tests/functional/utils/CMakeLists.txt index 5c6577b24e..ff175283f8 100644 --- a/Release/tests/functional/utils/CMakeLists.txt +++ b/Release/tests/functional/utils/CMakeLists.txt @@ -8,8 +8,8 @@ set(SOURCES stdafx.cpp ) -add_casablanca_test(${LIB}utils_test SOURCES) +add_casablanca_test(utils_test SOURCES) if(CMAKE_COMPILER_IS_GNUCXX) - target_compile_options(${LIB}utils_test PRIVATE "-Wno-deprecated-declarations") -endif() \ No newline at end of file + target_compile_options(utils_test PRIVATE "-Wno-deprecated-declarations") +endif() diff --git a/Release/tests/functional/websockets/CMakeLists.txt b/Release/tests/functional/websockets/CMakeLists.txt index b232922576..889a4e0484 100644 --- a/Release/tests/functional/websockets/CMakeLists.txt +++ b/Release/tests/functional/websockets/CMakeLists.txt @@ -1,10 +1,5 @@ if (NOT CPPREST_EXCLUDE_WEBSOCKETS) - - set(SOURCES - utilities/test_websocket_server.cpp - ) - - add_library(websockettest_utilities ${SOURCES}) + add_library(websockettest_utilities utilities/test_websocket_server.cpp) target_include_directories(websockettest_utilities PUBLIC utilities) target_compile_definitions(websockettest_utilities PRIVATE -DWEBSOCKETTESTUTILITY_EXPORTS) if(NOT WIN32) @@ -15,11 +10,25 @@ if (NOT CPPREST_EXCLUDE_WEBSOCKETS) cpprest_find_websocketpp() target_link_libraries(websockettest_utilities PRIVATE - unittestpp cpprest + unittestpp common_utilities cpprestsdk_websocketpp_internal ) - add_subdirectory(client) + # websocketsclient_test + set(SOURCES + client/authentication_tests.cpp + client/client_construction.cpp + client/close_tests.cpp + client/error_tests.cpp + client/receive_msg_tests.cpp + client/send_msg_tests.cpp + client/stdafx.cpp + ) + + add_casablanca_test(websocketsclient_test SOURCES) + if(NOT TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT") + target_link_libraries(websocketsclient_test PRIVATE websockettest_utilities) + endif() endif() diff --git a/Release/tests/functional/websockets/client/CMakeLists.txt b/Release/tests/functional/websockets/client/CMakeLists.txt deleted file mode 100644 index bda6b6e6a8..0000000000 --- a/Release/tests/functional/websockets/client/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -if (NOT CPPREST_EXCLUDE_WEBSOCKETS) - set(SOURCES - authentication_tests.cpp - client_construction.cpp - close_tests.cpp - error_tests.cpp - receive_msg_tests.cpp - send_msg_tests.cpp - stdafx.cpp - ) - - # This works around "OBJECT" tests - link_libraries(websockettest_utilities) - add_casablanca_test(websocketclient_test SOURCES) -endif() \ No newline at end of file From b0634729ae3ece059f5d727e6176f9bf8b9a0e77 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sun, 5 Nov 2017 00:47:17 -0700 Subject: [PATCH 150/438] Refactor out uri_parser, moving it into the underlying uri implementation --- Release/include/cpprest/asyncrt_utils.h | 14 +- Release/include/cpprest/base_uri.h | 115 +--- Release/include/cpprest/details/uri_parser.h | 201 ------- Release/include/cpprest/uri_builder.h | 52 +- Release/src/CMakeLists.txt | 2 +- Release/src/build/common.vcxitems | 188 +++--- Release/src/build/common.vcxitems.filters | 464 +++++++-------- Release/src/pch/stdafx.h | 1 - Release/src/uri/uri.cpp | 534 ++++++++++++++++-- Release/src/uri/uri_builder.cpp | 30 +- Release/src/uri/uri_parser.cpp | 352 ------------ .../tests/functional/uri/encoding_tests.cpp | 8 +- 12 files changed, 888 insertions(+), 1073 deletions(-) delete mode 100644 Release/include/cpprest/details/uri_parser.h delete mode 100644 Release/src/uri/uri_parser.cpp diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index fac70a91a9..85d94438fc 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -269,6 +269,16 @@ namespace conversions return val; } + template + utf8string print_utf8string(const Source& val) + { + return conversions::to_utf8string(print_string(val)); + } + inline const utf8string& print_utf8string(const utf8string& val) + { + return val; + } + template Target scan_string(const utility::string_t &str) { @@ -407,9 +417,9 @@ class windows_category_impl : public std::error_category public: virtual const char *name() const CPPREST_NOEXCEPT { return "windows"; } - _ASYNCRTIMP virtual std::string message(int errorCode) const CPPREST_NOEXCEPT; + virtual std::string message(int errorCode) const CPPREST_NOEXCEPT; - _ASYNCRTIMP virtual std::error_condition default_error_condition(int errorCode) const CPPREST_NOEXCEPT; + virtual std::error_condition default_error_condition(int errorCode) const CPPREST_NOEXCEPT; }; /// diff --git a/Release/include/cpprest/base_uri.h b/Release/include/cpprest/base_uri.h index a8b0f54ff4..1d2874a41b 100644 --- a/Release/include/cpprest/base_uri.h +++ b/Release/include/cpprest/base_uri.h @@ -27,58 +27,13 @@ namespace web { { struct uri_components { - uri_components() : m_path(_XPLATSTR("/")), m_port(-1) - {} - - uri_components(const uri_components &other) : - m_scheme(other.m_scheme), - m_host(other.m_host), - m_user_info(other.m_user_info), - m_path(other.m_path), - m_query(other.m_query), - m_fragment(other.m_fragment), - m_port(other.m_port) - {} - - uri_components & operator=(const uri_components &other) - { - if (this != &other) - { - m_scheme = other.m_scheme; - m_host = other.m_host; - m_user_info = other.m_user_info; - m_path = other.m_path; - m_query = other.m_query; - m_fragment = other.m_fragment; - m_port = other.m_port; - } - return *this; - } - - uri_components(uri_components &&other) CPPREST_NOEXCEPT : - m_scheme(std::move(other.m_scheme)), - m_host(std::move(other.m_host)), - m_user_info(std::move(other.m_user_info)), - m_path(std::move(other.m_path)), - m_query(std::move(other.m_query)), - m_fragment(std::move(other.m_fragment)), - m_port(other.m_port) - {} - - uri_components & operator=(uri_components &&other) CPPREST_NOEXCEPT - { - if (this != &other) - { - m_scheme = std::move(other.m_scheme); - m_host = std::move(other.m_host); - m_user_info = std::move(other.m_user_info); - m_path = std::move(other.m_path); - m_query = std::move(other.m_query); - m_fragment = std::move(other.m_fragment); - m_port = other.m_port; - } - return *this; - } + uri_components() : m_path(_XPLATSTR("/")), m_port(-1) {} + + uri_components(const uri_components &other) = default; + uri_components & operator=(const uri_components &other) = default; + + uri_components(uri_components &&other) = default; + uri_components & operator=(uri_components &&other) = default; _ASYNCRTIMP utility::string_t join(); @@ -174,9 +129,8 @@ namespace web { /// Encodes a string by converting all characters except for RFC 3986 unreserved characters to their /// hexadecimal representation. /// - /// The UTF-8 string data. /// The encoded string. - _ASYNCRTIMP static utility::string_t __cdecl encode_data_string(const utility::string_t &utf8data); + _ASYNCRTIMP static utility::string_t __cdecl encode_data_string(const utility::string_t &data); /// /// Decodes an encoded string. @@ -202,6 +156,9 @@ namespace web { /// /// Validates a string as a URI. /// + /// + /// This function accepts both uris ('http://msn.com/') and uri relative-references ('path1/path2?query'). + /// /// The URI string to be validated. /// true if the given string represents a valid URI, false otherwise. _ASYNCRTIMP static bool __cdecl validate(const utility::string_t &uri_string); @@ -209,13 +166,7 @@ namespace web { /// /// Creates an empty uri /// - uri() { m_uri = _XPLATSTR("/");}; - - /// - /// Creates a URI from the given URI components. - /// - /// A URI components object to create the URI instance. - _ASYNCRTIMP uri(const details::uri_components &components); + uri() : m_uri(_XPLATSTR("/")) {} /// /// Creates a URI from the given encoded string. This will throw an exception if the string @@ -234,44 +185,22 @@ namespace web { /// /// Copy constructor. /// - uri(const uri &other) : - m_uri(other.m_uri), - m_components(other.m_components) - {} + uri(const uri &other) = default; /// /// Copy assignment operator. /// - uri & operator=(const uri &other) - { - if (this != &other) - { - m_uri = other.m_uri; - m_components = other.m_components; - } - return *this; - } + uri & operator=(const uri &other) = default; /// /// Move constructor. /// - uri(uri &&other) CPPREST_NOEXCEPT : - m_uri(std::move(other.m_uri)), - m_components(std::move(other.m_components)) - {} + uri(uri &&other) = default; /// /// Move assignment operator /// - uri & operator=(uri &&other) CPPREST_NOEXCEPT - { - if (this != &other) - { - m_uri = std::move(other.m_uri); - m_components = std::move(other.m_components); - } - return *this; - } + uri & operator=(uri &&other) = default; /// /// Get the scheme component of the URI as an encoded string. @@ -372,7 +301,7 @@ namespace web { return !(is_empty() || is_host_loopback() || is_host_wildcard()); } - // + /// /// A default port is one where the port is unspecified, and will be determined by the operating system. /// The choice of default port may be dictated by the scheme (http -> 80) or not. /// @@ -434,8 +363,14 @@ namespace web { private: friend class uri_builder; - // Encodes all characters not in given set determined by given function. - _ASYNCRTIMP static utility::string_t __cdecl encode_impl(const utility::string_t &raw, const std::function& should_encode); + /// + /// Creates a URI from the given URI components. + /// + /// A URI components object to create the URI instance. + _ASYNCRTIMP uri(const details::uri_components &components); + + // Used by uri_builder + static utility::string_t __cdecl encode_query_impl(const utf8string& raw); utility::string_t m_uri; details::uri_components m_components; diff --git a/Release/include/cpprest/details/uri_parser.h b/Release/include/cpprest/details/uri_parser.h deleted file mode 100644 index e1b43db85c..0000000000 --- a/Release/include/cpprest/details/uri_parser.h +++ /dev/null @@ -1,201 +0,0 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* URI parsing implementation -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ - -#pragma once - -#include - -namespace web { namespace details -{ - namespace uri_parser - { - - /// - /// Parses the uri, attempting to determine its validity. - /// - /// This function accepts both uris ('http://msn.com/') and uri relative-references ('path1/path2?query') - /// - bool validate(const utility::string_t &encoded_string); - - /// - /// Parses the uri, setting each provided string to the value of that component. Components - /// that are not part of the provided text are set to the empty string. Component strings - /// DO NOT contain their beginning or ending delimiters. - /// - /// This function accepts both uris ('http://msn.com/') and uri relative-references ('path1/path2?query') - /// - bool parse(const utility::string_t &encoded_string, uri_components &components); - - /// - /// Unreserved characters are those that are allowed in a URI but do not have a reserved purpose. They include: - /// - A-Z - /// - a-z - /// - 0-9 - /// - '-' (hyphen) - /// - '.' (period) - /// - '_' (underscore) - /// - '~' (tilde) - /// - inline bool is_unreserved(int c) - { - return ::utility::details::is_alnum((char)c) || c == '-' || c == '.' || c == '_' || c == '~'; - } - - /// - /// General delimiters serve as the delimiters between different uri components. - /// General delimiters include: - /// - All of these :/?#[]@ - /// - inline bool is_gen_delim(int c) - { - return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@'; - } - - /// - /// Subdelimiters are those characters that may have a defined meaning within component - /// of a uri for a particular scheme. They do not serve as delimiters in any case between - /// uri segments. sub_delimiters include: - /// - All of these !$&'()*+,;= - /// - inline bool is_sub_delim(int c) - { - switch (c) - { - case '!': - case '$': - case '&': - case '\'': - case '(': - case ')': - case '*': - case '+': - case ',': - case ';': - case '=': - return true; - default: - return false; - } - } - - /// - /// Reserved characters includes the general delimiters and sub delimiters. Some characters - /// are neither reserved nor unreserved, and must be percent-encoded. - /// - inline bool is_reserved(int c) - { - return is_gen_delim(c) || is_sub_delim(c); - } - - /// - /// Legal characters in the scheme portion include: - /// - Any alphanumeric character - /// - '+' (plus) - /// - '-' (hyphen) - /// - '.' (period) - /// - /// Note that the scheme must BEGIN with an alpha character. - /// - inline bool is_scheme_character(int c) - { - return ::utility::details::is_alnum((char)c) || c == '+' || c == '-' || c == '.'; - } - - /// - /// Legal characters in the user information portion include: - /// - Any unreserved character - /// - The percent character ('%'), and thus any percent-endcoded octet - /// - The sub-delimiters - /// - ':' (colon) - /// - inline bool is_user_info_character(int c) - { - return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == ':'; - } - - /// - /// Legal characters in the host portion include: - /// - Any unreserved character - /// - The percent character ('%'), and thus any percent-endcoded octet - /// - The sub-delimiters - /// - ':' (colon) - /// - '[' (open bracket) - /// - ']' (close bracket) - /// - inline bool is_host_character(int c) - { - return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == ':' || c == '[' || c == ']'; - } - - /// - /// Legal characters in the authority portion include: - /// - Any unreserved character - /// - The percent character ('%'), and thus any percent-endcoded octet - /// - The sub-delimiters - /// - ':' (colon) - /// - IPv6 requires '[]' allowed for it to be valid URI and passed to underlying platform for IPv6 support - /// - inline bool is_authority_character(int c) - { - return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == '@' || c == ':' || c == '[' || c == ']'; - } - - /// - /// Legal characters in the path portion include: - /// - Any unreserved character - /// - The percent character ('%'), and thus any percent-endcoded octet - /// - The sub-delimiters - /// - ':' (colon) - /// - '@' (ampersand) - /// - inline bool is_path_character(int c) - { - return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == '/' || c == ':' || c == '@'; - } - - /// - /// Legal characters in the query portion include: - /// - Any path character - /// - '?' (question mark) - /// - inline bool is_query_character(int c) - { - return is_path_character(c) || c == '?'; - } - - /// - /// Legal characters in the fragment portion include: - /// - Any path character - /// - '?' (question mark) - /// - inline bool is_fragment_character(int c) - { - // this is intentional, they have the same set of legal characters - return is_query_character(c); - } - - /// - /// Parses the uri, setting the given pointers to locations inside the given buffer. - /// 'encoded' is expected to point to an encoded zero-terminated string containing a uri - /// - bool inner_parse( - const utility::char_t *encoded, - const utility::char_t **scheme_begin, const utility::char_t **scheme_end, - const utility::char_t **uinfo_begin, const utility::char_t **uinfo_end, - const utility::char_t **host_begin, const utility::char_t **host_end, - _Out_ int *port, - const utility::char_t **path_begin, const utility::char_t **path_end, - const utility::char_t **query_begin, const utility::char_t **query_end, - const utility::char_t **fragment_begin, const utility::char_t **fragment_end); - } -}} diff --git a/Release/include/cpprest/uri_builder.h b/Release/include/cpprest/uri_builder.h index 4827534249..6e03e5e2c0 100644 --- a/Release/include/cpprest/uri_builder.h +++ b/Release/include/cpprest/uri_builder.h @@ -18,7 +18,6 @@ #include #include "cpprest/base_uri.h" -#include "cpprest/details/uri_parser.h" namespace web { @@ -32,7 +31,7 @@ namespace web /// /// Creates a builder with an initially empty URI. /// - uri_builder() {} + uri_builder() = default; /// /// Creates a builder with a existing URI object. @@ -134,18 +133,7 @@ namespace web /// Port as a string. /// A reference to this uri_builder to support chaining. /// When string can't be converted to an integer the port is left unchanged. - uri_builder & set_port(const utility::string_t &port) - { - utility::istringstream_t portStream(port); - int port_tmp; - portStream >> port_tmp; - if(portStream.fail() || portStream.bad()) - { - throw std::invalid_argument("invalid port argument, must be non empty string containing integer value"); - } - m_uri.m_port = port_tmp; - return *this; - } + _ASYNCRTIMP uri_builder & set_port(const utility::string_t &port); /// /// Set the path component of the URI. @@ -225,36 +213,11 @@ namespace web template uri_builder &append_query(const utility::string_t &name, const T &value, bool do_encoding = true) { - auto encodedName = name; - auto encodedValue = utility::conversions::details::print_string(value); - if (do_encoding) - { - auto encodingCheck = [](int ch) - { - switch (ch) - { - // Encode '&', ';', and '=' since they are used - // as delimiters in query component. - case '&': - case ';': - case '=': - case '%': - case '+': - return true; - default: - return !::web::details::uri_parser::is_query_character(ch); - } - }; - encodedName = uri::encode_impl(encodedName, encodingCheck); - encodedValue = uri::encode_impl(encodedValue, encodingCheck); - } - - auto encodedQuery = encodedName; - encodedQuery.append(_XPLATSTR("=")); - encodedQuery.append(encodedValue); - // The query key value pair was already encoded by us or the user separately. - return append_query(encodedQuery, false); + append_query_encode_impl(name, utility::conversions::details::print_utf8string(value)); + else + append_query_no_encode_impl(name, utility::conversions::details::print_string(value)); + return *this; } /// @@ -276,6 +239,9 @@ namespace web _ASYNCRTIMP bool is_valid(); private: + _ASYNCRTIMP void append_query_encode_impl(const utility::string_t &name, const utf8string &value); + _ASYNCRTIMP void append_query_no_encode_impl(const utility::string_t &name, const utility::string_t &value); + details::uri_components m_uri; }; } // namespace web diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index e01e075707..cfe3dbe760 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -12,6 +12,7 @@ source_group("Header Files\\pplx" FILES ${HEADERS_PPLX}) source_group("Header Files\\cpprest\\details" FILES ${HEADERS_DETAILS}) list(FILTER HEADERS_PPLX EXCLUDE REGEX "threadpool\\.h") + set(SOURCES ${HEADERS_CPPREST} ${HEADERS_PPLX} @@ -36,7 +37,6 @@ set(SOURCES pplx/pplx.cpp uri/uri.cpp uri/uri_builder.cpp - uri/uri_parser.cpp utilities/asyncrt_utils.cpp utilities/base64.cpp utilities/web_utilities.cpp diff --git a/Release/src/build/common.vcxitems b/Release/src/build/common.vcxitems index 8e9142fa9a..4abeacb737 100644 --- a/Release/src/build/common.vcxitems +++ b/Release/src/build/common.vcxitems @@ -1,95 +1,95 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 248F659F-DAC5-46E8-AC09-60EC9FC95053 - true - b19fa703-0bf0-4e1f-8927-b0eaeb6aa823 - {594dcb5f-07e3-4084-a2ce-268611fa629f} - common - common - - - - %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) - - - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + 248F659F-DAC5-46E8-AC09-60EC9FC95053 + true + b19fa703-0bf0-4e1f-8927-b0eaeb6aa823 + {594dcb5f-07e3-4084-a2ce-268611fa629f} + common + common + + + + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + + + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Release/src/build/common.vcxitems.filters b/Release/src/build/common.vcxitems.filters index 437868082e..8839f755df 100644 --- a/Release/src/build/common.vcxitems.filters +++ b/Release/src/build/common.vcxitems.filters @@ -1,233 +1,233 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - {3bdf9ddb-6199-4b83-84cd-e8617e78294e} - - - {42f86193-fcdc-443d-8ede-8fd31abe6643} - - - {ed89d519-15d6-47d9-90cb-e6c25bcaa323} - - - {e5ecd256-178a-403a-9249-5d15463ad051} - - - {d32b3879-7333-4ab4-8ef2-dd72aed7b5dc} - - - {1c12997c-5bf5-4b60-853e-a5f9c8303760} - - - {97da7aee-41c8-4948-bb0e-c31cec1bfb16} - - - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\pch - - - Header Files\pplx - - - Header Files\pplx - - - Header Files\pplx - - - Header Files\pplx - - - Header Files\pplx - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest - - - Header Files\cpprest\details - - - Header Files\private - - - Header Files\private - - - Header Files\private - - - Header Files\private - - - - - Header Files\cpprest\details - - + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + {3bdf9ddb-6199-4b83-84cd-e8617e78294e} + + + {42f86193-fcdc-443d-8ede-8fd31abe6643} + + + {ed89d519-15d6-47d9-90cb-e6c25bcaa323} + + + {e5ecd256-178a-403a-9249-5d15463ad051} + + + {d32b3879-7333-4ab4-8ef2-dd72aed7b5dc} + + + {1c12997c-5bf5-4b60-853e-a5f9c8303760} + + + {97da7aee-41c8-4948-bb0e-c31cec1bfb16} + + + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\pch + + + Header Files\pplx + + + Header Files\pplx + + + Header Files\pplx + + + Header Files\pplx + + + Header Files\pplx + + + Header Files\cpprest\details + + + Header Files\cpprest\details + + + Header Files\cpprest + + + Header Files\cpprest\details + + + Header Files\private + + + Header Files\private + + + Header Files\private + + + Header Files\private + + + + + Header Files\cpprest\details + + \ No newline at end of file diff --git a/Release/src/pch/stdafx.h b/Release/src/pch/stdafx.h index 05a004dec4..6f61163dfe 100644 --- a/Release/src/pch/stdafx.h +++ b/Release/src/pch/stdafx.h @@ -111,7 +111,6 @@ // uri #include "cpprest/base_uri.h" -#include "cpprest/details/uri_parser.h" // utilities #include "cpprest/asyncrt_utils.h" diff --git a/Release/src/uri/uri.cpp b/Release/src/uri/uri.cpp index 3157b96a6d..f257787e94 100644 --- a/Release/src/uri/uri.cpp +++ b/Release/src/uri/uri.cpp @@ -17,6 +17,436 @@ using namespace utility::conversions; namespace web { namespace details { +namespace +{ + /// + /// Unreserved characters are those that are allowed in a URI but do not have a reserved purpose. They include: + /// - A-Z + /// - a-z + /// - 0-9 + /// - '-' (hyphen) + /// - '.' (period) + /// - '_' (underscore) + /// - '~' (tilde) + /// + inline bool is_unreserved(int c) + { + return ::utility::details::is_alnum((char)c) || c == '-' || c == '.' || c == '_' || c == '~'; + } + + /// + /// General delimiters serve as the delimiters between different uri components. + /// General delimiters include: + /// - All of these :/?#[]@ + /// + inline bool is_gen_delim(int c) + { + return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@'; + } + + /// + /// Subdelimiters are those characters that may have a defined meaning within component + /// of a uri for a particular scheme. They do not serve as delimiters in any case between + /// uri segments. sub_delimiters include: + /// - All of these !$&'()*+,;= + /// + inline bool is_sub_delim(int c) + { + switch (c) + { + case '!': + case '$': + case '&': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case ';': + case '=': + return true; + default: + return false; + } + } + + /// + /// Reserved characters includes the general delimiters and sub delimiters. Some characters + /// are neither reserved nor unreserved, and must be percent-encoded. + /// + inline bool is_reserved(int c) + { + return is_gen_delim(c) || is_sub_delim(c); + } + + /// + /// Legal characters in the scheme portion include: + /// - Any alphanumeric character + /// - '+' (plus) + /// - '-' (hyphen) + /// - '.' (period) + /// + /// Note that the scheme must BEGIN with an alpha character. + /// + inline bool is_scheme_character(int c) + { + return ::utility::details::is_alnum((char)c) || c == '+' || c == '-' || c == '.'; + } + + /// + /// Legal characters in the user information portion include: + /// - Any unreserved character + /// - The percent character ('%'), and thus any percent-endcoded octet + /// - The sub-delimiters + /// - ':' (colon) + /// + inline bool is_user_info_character(int c) + { + return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == ':'; + } + + /// + /// Legal characters in the host portion include: + /// - Any unreserved character + /// - The percent character ('%'), and thus any percent-endcoded octet + /// - The sub-delimiters + /// - ':' (colon) + /// - '[' (open bracket) + /// - ']' (close bracket) + /// + inline bool is_host_character(int c) + { + return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == ':' || c == '[' || c == ']'; + } + + /// + /// Legal characters in the authority portion include: + /// - Any unreserved character + /// - The percent character ('%'), and thus any percent-endcoded octet + /// - The sub-delimiters + /// - ':' (colon) + /// - IPv6 requires '[]' allowed for it to be valid URI and passed to underlying platform for IPv6 support + /// + inline bool is_authority_character(int c) + { + return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == '@' || c == ':' || c == '[' || c == ']'; + } + + /// + /// Legal characters in the path portion include: + /// - Any unreserved character + /// - The percent character ('%'), and thus any percent-endcoded octet + /// - The sub-delimiters + /// - ':' (colon) + /// - '@' (ampersand) + /// + inline bool is_path_character(int c) + { + return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == '/' || c == ':' || c == '@'; + } + + /// + /// Legal characters in the query portion include: + /// - Any path character + /// - '?' (question mark) + /// + inline bool is_query_character(int c) + { + return is_path_character(c) || c == '?'; + } + + /// + /// Legal characters in the fragment portion include: + /// - Any path character + /// - '?' (question mark) + /// + inline bool is_fragment_character(int c) + { + // this is intentional, they have the same set of legal characters + return is_query_character(c); + } + + struct inner_parse_out + { + const utility::char_t *scheme_begin = nullptr; + const utility::char_t *scheme_end = nullptr; + const utility::char_t *uinfo_begin = nullptr; + const utility::char_t *uinfo_end = nullptr; + const utility::char_t *host_begin = nullptr; + const utility::char_t *host_end = nullptr; + int port = 0; + const utility::char_t *path_begin = nullptr; + const utility::char_t *path_end = nullptr; + const utility::char_t *query_begin = nullptr; + const utility::char_t *query_end = nullptr; + const utility::char_t *fragment_begin = nullptr; + const utility::char_t *fragment_end = nullptr; + + /// + /// Parses the uri, setting the given pointers to locations inside the given buffer. + /// 'encoded' is expected to point to an encoded zero-terminated string containing a uri + /// + bool parse_from(const utility::char_t *encoded) + { + const utility::char_t *p = encoded; + + // IMPORTANT -- A uri may either be an absolute uri, or an relative-reference + // Absolute: 'http://host.com/' + // Relative-Reference: '//:host.com', '/path1/path2?query', './path1:path2' + // A Relative-Reference can be disambiguated by parsing for a ':' before the first slash + + bool is_relative_reference = true; + const utility::char_t *p2 = p; + for (; *p2 != _XPLATSTR('/') && *p2 != _XPLATSTR('\0'); p2++) + { + if (*p2 == _XPLATSTR(':')) + { + // found a colon, the first portion is a scheme + is_relative_reference = false; + break; + } + } + + if (!is_relative_reference) + { + // the first character of a scheme must be a letter + if (!isalpha(*p)) + { + return false; + } + + // start parsing the scheme, it's always delimited by a colon (must be present) + scheme_begin = p++; + for (; *p != ':'; p++) + { + if (!is_scheme_character(*p)) + { + return false; + } + } + scheme_end = p; + + // skip over the colon + p++; + } + + // if we see two slashes next, then we're going to parse the authority portion + // later on we'll break up the authority into the port and host + const utility::char_t *authority_begin = nullptr; + const utility::char_t *authority_end = nullptr; + if (*p == _XPLATSTR('/') && p[1] == _XPLATSTR('/')) + { + // skip over the slashes + p += 2; + authority_begin = p; + + // the authority is delimited by a slash (resource), question-mark (query) or octothorpe (fragment) + // or by EOS. The authority could be empty ('file:///C:\file_name.txt') + for (; *p != _XPLATSTR('/') && *p != _XPLATSTR('?') && *p != _XPLATSTR('#') && *p != _XPLATSTR('\0'); p++) + { + // We're NOT currently supporting IPvFuture or username/password in authority + // IPv6 as the host (i.e. http://[:::::::]) is allowed as valid URI and passed to subsystem for support. + if (!is_authority_character(*p)) + { + return false; + } + } + authority_end = p; + + // now lets see if we have a port specified -- by working back from the end + if (authority_begin != authority_end) + { + // the port is made up of all digits + const utility::char_t *port_begin = authority_end - 1; + for (; isdigit(*port_begin) && port_begin != authority_begin; port_begin--) + { + } + + if (*port_begin == _XPLATSTR(':')) + { + // has a port + host_begin = authority_begin; + host_end = port_begin; + + //skip the colon + port_begin++; + + port = utility::conversions::details::scan_string(utility::string_t(port_begin, authority_end)); + } + else + { + // no port + host_begin = authority_begin; + host_end = authority_end; + } + + // look for a user_info component + const utility::char_t *u_end = host_begin; + for (; is_user_info_character(*u_end) && u_end != host_end; u_end++) + { + } + + if (*u_end == _XPLATSTR('@')) + { + host_begin = u_end + 1; + uinfo_begin = authority_begin; + uinfo_end = u_end; + } + } + } + + // if we see a path character or a slash, then the + // if we see a slash, or any other legal path character, parse the path next + if (*p == _XPLATSTR('/') || is_path_character(*p)) + { + path_begin = p; + + // the path is delimited by a question-mark (query) or octothorpe (fragment) or by EOS + for (; *p != _XPLATSTR('?') && *p != _XPLATSTR('#') && *p != _XPLATSTR('\0'); p++) + { + if (!is_path_character(*p)) + { + return false; + } + } + path_end = p; + } + + // if we see a ?, then the query is next + if (*p == _XPLATSTR('?')) + { + // skip over the question mark + p++; + query_begin = p; + + // the query is delimited by a '#' (fragment) or EOS + for (; *p != _XPLATSTR('#') && *p != _XPLATSTR('\0'); p++) + { + if (!is_query_character(*p)) + { + return false; + } + } + query_end = p; + } + + // if we see a #, then the fragment is next + if (*p == _XPLATSTR('#')) + { + // skip over the hash mark + p++; + fragment_begin = p; + + // the fragment is delimited by EOS + for (; *p != _XPLATSTR('\0'); p++) + { + if (!is_fragment_character(*p)) + { + return false; + } + } + fragment_end = p; + } + + return true; + } + + void write_to(uri_components& components) + { + 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); + }); + } + else + { + components.m_scheme.clear(); + } + + if (uinfo_begin) + { + components.m_user_info.assign(uinfo_begin, uinfo_end); + } + + 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); + }); + } + else + { + components.m_host.clear(); + } + + components.m_port = port; + + if (path_begin) + { + components.m_path.assign(path_begin, path_end); + } + else + { + // default path to begin with a slash for easy comparison + components.m_path = _XPLATSTR("/"); + } + + if (query_begin) + { + components.m_query.assign(query_begin, query_end); + } + else + { + components.m_query.clear(); + } + + if (fragment_begin) + { + components.m_fragment.assign(fragment_begin, fragment_end); + } + else + { + components.m_fragment.clear(); + } + } + }; + + // Encodes all characters not in given set determined by given function. + template + utility::string_t encode_impl(const utf8string &raw, F should_encode) + { + const utility::char_t * const hex = _XPLATSTR("0123456789ABCDEF"); + utility::string_t encoded; + for (auto iter = raw.begin(); iter != raw.end(); ++iter) + { + // for utf8 encoded string, char ASCII can be greater than 127. + int ch = static_cast(*iter); + // ch should be same under both utf8 and utf16. + if (should_encode(ch)) + { + encoded.push_back(_XPLATSTR('%')); + encoded.push_back(hex[(ch >> 4) & 0xF]); + encoded.push_back(hex[ch & 0xF]); + } + else + { + // ASCII don't need to be encoded, which should be same on both utf8 and utf16. + encoded.push_back((utility::char_t)ch); + } + } + return encoded; + } + +} + utility::string_t uri_components::join() { // canonicalize components first @@ -90,114 +520,109 @@ utility::string_t uri_components::join() } } -using namespace details; - uri::uri(const details::uri_components &components) : m_components(components) { m_uri = m_components.join(); - if (!details::uri_parser::validate(m_uri)) + + if (!uri::validate(m_uri.c_str())) { throw uri_exception("provided uri is invalid: " + utility::conversions::to_utf8string(m_uri)); } } -uri::uri(const utility::string_t &uri_string) -{ - if (!details::uri_parser::parse(uri_string, m_components)) - { - throw uri_exception("provided uri is invalid: " + utility::conversions::to_utf8string(uri_string)); - } - m_uri = m_components.join(); -} +uri::uri(const utility::string_t &uri_string) : uri(uri_string.c_str()) {} -uri::uri(const utility::char_t *uri_string): m_uri(uri_string) +uri::uri(const utility::char_t *uri_string) { - if (!details::uri_parser::parse(uri_string, m_components)) + details::inner_parse_out out; + + if (!out.parse_from(uri_string)) { throw uri_exception("provided uri is invalid: " + utility::conversions::to_utf8string(uri_string)); } + + out.write_to(m_components); m_uri = m_components.join(); } -utility::string_t uri::encode_impl(const utility::string_t &raw, const std::function& should_encode) +utility::string_t uri::encode_query_impl(const utf8string & raw) { - const utility::char_t * const hex = _XPLATSTR("0123456789ABCDEF"); - utility::string_t encoded; - std::string utf8raw = to_utf8string(raw); - for (auto iter = utf8raw.begin(); iter != utf8raw.end(); ++iter) - { - // for utf8 encoded string, char ASCII can be greater than 127. - int ch = static_cast(*iter); - // ch should be same under both utf8 and utf16. - if(should_encode(ch)) - { - encoded.push_back(_XPLATSTR('%')); - encoded.push_back(hex[(ch >> 4) & 0xF]); - encoded.push_back(hex[ch & 0xF]); - } - else + return details::encode_impl(raw, [](int ch) -> bool + { + switch (ch) { - // ASCII don't need to be encoded, which should be same on both utf8 and utf16. - encoded.push_back((utility::char_t)ch); + // Encode '&', ';', and '=' since they are used + // as delimiters in query component. + case '&': + case ';': + case '=': + case '%': + case '+': + return true; + default: + return !details::is_query_character(ch); } - } - return encoded; + }); } /// /// Encodes a string by converting all characters except for RFC 3986 unreserved characters to their /// hexadecimal representation. /// -utility::string_t uri::encode_data_string(const utility::string_t &raw) +utility::string_t uri::encode_data_string(const utility::string_t &data) { - return uri::encode_impl(raw, [](int ch) -> bool + auto&& raw = utility::conversions::to_utf8string(data); + + return details::encode_impl(raw, [](int ch) -> bool { - return !uri_parser::is_unreserved(ch); + return !details::is_unreserved(ch); }); } utility::string_t uri::encode_uri(const utility::string_t &raw, uri::components::component component) { + auto&& raw_utf8 = utility::conversions::to_utf8string(raw); + // Note: we also encode the '+' character because some non-standard implementations // encode the space character as a '+' instead of %20. To better interoperate we encode // '+' to avoid any confusion and be mistaken as a space. switch(component) { case components::user_info: - return uri::encode_impl(raw, [](int ch) -> bool + return details::encode_impl(raw_utf8, [](int ch) -> bool { - return !uri_parser::is_user_info_character(ch) + return !details::is_user_info_character(ch) || ch == '%' || ch == '+'; }); case components::host: - return uri::encode_impl(raw, [](int ch) -> bool + return details::encode_impl(raw_utf8, [](int ch) -> bool { // No encoding of ASCII characters in host name (RFC 3986 3.2.2) return ch > 127; }); case components::path: - return uri::encode_impl(raw, [](int ch) -> bool + return details::encode_impl(raw_utf8, [](int ch) -> bool { - return !uri_parser::is_path_character(ch) + return !details::is_path_character(ch) || ch == '%' || ch == '+'; }); case components::query: - return uri::encode_impl(raw, [](int ch) -> bool + return details::encode_impl(raw_utf8, [](int ch) -> bool { - return !uri_parser::is_query_character(ch) + return !details::is_query_character(ch) || ch == '%' || ch == '+'; }); case components::fragment: - return uri::encode_impl(raw, [](int ch) -> bool + return details::encode_impl(raw_utf8, [](int ch) -> bool { - return !uri_parser::is_fragment_character(ch) + return !details::is_fragment_character(ch) || ch == '%' || ch == '+'; }); case components::full_uri: default: - return uri::encode_impl(raw, [](int ch) -> bool + return details::encode_impl(raw_utf8, [](int ch) -> bool { - return !uri_parser::is_unreserved(ch) && !uri_parser::is_reserved(ch); + return !details::is_unreserved(ch) && !details::is_reserved(ch); }); }; } @@ -230,7 +655,7 @@ static int hex_char_digit_to_decimal_char(int hex) utility::string_t uri::decode(const utility::string_t &encoded) { - std::string utf8raw; + utf8string raw; for(auto iter = encoded.begin(); iter != encoded.end(); ++iter) { if(*iter == _XPLATSTR('%')) @@ -246,15 +671,19 @@ utility::string_t uri::decode(const utility::string_t &encoded) } decimal_value += hex_char_digit_to_decimal_char(static_cast(*iter)); - utf8raw.push_back(static_cast(decimal_value)); + raw.push_back(static_cast(decimal_value)); + } + else if (*iter > CHAR_MAX || *iter < 0) + { + throw uri_exception("Invalid encoded URI string, must be entirely ascii"); } else { // encoded string has to be ASCII. - utf8raw.push_back(reinterpret_cast(*iter)); + raw.push_back(static_cast(*iter)); } } - return to_string_t(utf8raw); + return to_string_t(raw); } std::vector uri::split_path(const utility::string_t &path) @@ -315,7 +744,8 @@ std::map uri::split_query(const utility::s bool uri::validate(const utility::string_t &uri_string) { - return uri_parser::validate(uri_string); + details::inner_parse_out out; + return out.parse_from(uri_string.c_str()); } uri uri::authority() const diff --git a/Release/src/uri/uri_builder.cpp b/Release/src/uri/uri_builder.cpp index b7d08b6380..02dd024b9b 100644 --- a/Release/src/uri/uri_builder.cpp +++ b/Release/src/uri/uri_builder.cpp @@ -83,6 +83,20 @@ uri_builder &uri_builder::append_query(const utility::string_t &query, bool is_e return *this; } +uri_builder &uri_builder::set_port(const utility::string_t &port) +{ + utility::istringstream_t portStream(port); + portStream.imbue(std::locale::classic()); + int port_tmp; + portStream >> port_tmp; + if (portStream.fail() || portStream.bad()) + { + throw std::invalid_argument("invalid port argument, must be non empty string containing integer value"); + } + m_uri.m_port = port_tmp; + return *this; +} + uri_builder &uri_builder::append(const http::uri &relative_uri) { append_path(relative_uri.path()); @@ -106,5 +120,19 @@ bool uri_builder::is_valid() return uri::validate(m_uri.join()); } -} // namespace web +void uri_builder::append_query_encode_impl(const utility::string_t & name, const utf8string & value) +{ + utility::string_t encodedQuery = uri::encode_query_impl(utility::conversions::to_utf8string(name)); + encodedQuery.append(_XPLATSTR("=")); + encodedQuery.append(uri::encode_query_impl(value)); + + // The query key value pair was already encoded by us or the user separately. + append_query(encodedQuery, false); +} +void uri_builder::append_query_no_encode_impl(const utility::string_t & name, const utility::string_t & value) +{ + append_query(name + _XPLATSTR("=") + value, false); +} + +} // namespace web diff --git a/Release/src/uri/uri_parser.cpp b/Release/src/uri/uri_parser.cpp deleted file mode 100644 index 2778ae64a2..0000000000 --- a/Release/src/uri/uri_parser.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* URI parsing implementation -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ -#include "stdafx.h" -#include - -namespace web { namespace details { namespace uri_parser -{ - -bool validate(const utility::string_t &encoded_string) -{ - const utility::char_t *scheme_begin = nullptr; - const utility::char_t *scheme_end = nullptr; - const utility::char_t *uinfo_begin = nullptr; - const utility::char_t *uinfo_end = nullptr; - const utility::char_t *host_begin = nullptr; - const utility::char_t *host_end = nullptr; - int port_ptr = 0; - const utility::char_t *path_begin = nullptr; - const utility::char_t *path_end = nullptr; - const utility::char_t *query_begin = nullptr; - const utility::char_t *query_end = nullptr; - const utility::char_t *fragment_begin = nullptr; - const utility::char_t *fragment_end = nullptr; - - // perform a parse, but don't copy out the data - return inner_parse( - encoded_string.c_str(), - &scheme_begin, - &scheme_end, - &uinfo_begin, - &uinfo_end, - &host_begin, - &host_end, - &port_ptr, - &path_begin, - &path_end, - &query_begin, - &query_end, - &fragment_begin, - &fragment_end); -} - -bool parse(const utility::string_t &encoded_string, uri_components &components) -{ - const utility::char_t *scheme_begin = nullptr; - const utility::char_t *scheme_end = nullptr; - const utility::char_t *host_begin = nullptr; - const utility::char_t *host_end = nullptr; - const utility::char_t *uinfo_begin = nullptr; - const utility::char_t *uinfo_end = nullptr; - int port_ptr = 0; - const utility::char_t *path_begin = nullptr; - const utility::char_t *path_end = nullptr; - const utility::char_t *query_begin = nullptr; - const utility::char_t *query_end = nullptr; - const utility::char_t *fragment_begin = nullptr; - const utility::char_t *fragment_end = nullptr; - - if (inner_parse( - encoded_string.c_str(), - &scheme_begin, - &scheme_end, - &uinfo_begin, - &uinfo_end, - &host_begin, - &host_end, - &port_ptr, - &path_begin, - &path_end, - &query_begin, - &query_end, - &fragment_begin, - &fragment_end)) - { - 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); - }); - } - else - { - components.m_scheme.clear(); - } - - if (uinfo_begin) - { - components.m_user_info.assign(uinfo_begin, uinfo_end); - } - - 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); - }); - } - else - { - components.m_host.clear(); - } - - if (port_ptr) - { - components.m_port = port_ptr; - } - else - { - components.m_port = 0; - } - - if (path_begin) - { - components.m_path.assign(path_begin, path_end); - } - else - { - // default path to begin with a slash for easy comparison - components.m_path = _XPLATSTR("/"); - } - - if (query_begin) - { - components.m_query.assign(query_begin, query_end); - } - else - { - components.m_query.clear(); - } - - if (fragment_begin) - { - components.m_fragment.assign(fragment_begin, fragment_end); - } - else - { - components.m_fragment.clear(); - } - - return true; - } - else - { - return false; - } -} - -bool inner_parse( - const utility::char_t *encoded, - const utility::char_t **scheme_begin, const utility::char_t **scheme_end, - const utility::char_t **uinfo_begin, const utility::char_t **uinfo_end, - const utility::char_t **host_begin, const utility::char_t **host_end, - _Out_ int *port, - const utility::char_t **path_begin, const utility::char_t **path_end, - const utility::char_t **query_begin, const utility::char_t **query_end, - const utility::char_t **fragment_begin, const utility::char_t **fragment_end) -{ - *scheme_begin = nullptr; - *scheme_end = nullptr; - *uinfo_begin = nullptr; - *uinfo_end = nullptr; - *host_begin = nullptr; - *host_end = nullptr; - *port = 0; - *path_begin = nullptr; - *path_end = nullptr; - *query_begin = nullptr; - *query_end = nullptr; - *fragment_begin = nullptr; - *fragment_end = nullptr; - - const utility::char_t *p = encoded; - - // IMPORTANT -- A uri may either be an absolute uri, or an relative-reference - // Absolute: 'http://host.com/' - // Relative-Reference: '//:host.com', '/path1/path2?query', './path1:path2' - // A Relative-Reference can be disambiguated by parsing for a ':' before the first slash - - bool is_relative_reference = true; - const utility::char_t *p2 = p; - for (;*p2 != _XPLATSTR('/') && *p2 != _XPLATSTR('\0'); p2++) - { - if (*p2 == _XPLATSTR(':')) - { - // found a colon, the first portion is a scheme - is_relative_reference = false; - break; - } - } - - if (!is_relative_reference) - { - // the first character of a scheme must be a letter - if (!isalpha(*p)) - { - return false; - } - - // start parsing the scheme, it's always delimited by a colon (must be present) - *scheme_begin = p++; - for (;*p != ':'; p++) - { - if (!is_scheme_character(*p)) - { - return false; - } - } - *scheme_end = p; - - // skip over the colon - p++; - } - - // if we see two slashes next, then we're going to parse the authority portion - // later on we'll break up the authority into the port and host - const utility::char_t *authority_begin = nullptr; - const utility::char_t *authority_end = nullptr; - if (*p == _XPLATSTR('/') && p[1] == _XPLATSTR('/')) - { - // skip over the slashes - p += 2; - authority_begin = p; - - // the authority is delimited by a slash (resource), question-mark (query) or octothorpe (fragment) - // or by EOS. The authority could be empty ('file:///C:\file_name.txt') - for (;*p != _XPLATSTR('/') && *p != _XPLATSTR('?') && *p != _XPLATSTR('#') && *p != _XPLATSTR('\0'); p++) - { - // We're NOT currently supporting IPvFuture or username/password in authority - // IPv6 as the host (i.e. http://[:::::::]) is allowed as valid URI and passed to subsystem for support. - if (!is_authority_character(*p)) - { - return false; - } - } - authority_end = p; - - // now lets see if we have a port specified -- by working back from the end - if (authority_begin != authority_end) - { - // the port is made up of all digits - const utility::char_t *port_begin = authority_end - 1; - for (;isdigit(*port_begin) && port_begin != authority_begin; port_begin--) - { } - - if (*port_begin == _XPLATSTR(':')) - { - // has a port - *host_begin = authority_begin; - *host_end = port_begin; - - //skip the colon - port_begin++; - - *port = utility::conversions::details::scan_string(utility::string_t(port_begin, authority_end)); - } - else - { - // no port - *host_begin = authority_begin; - *host_end = authority_end; - } - - // look for a user_info component - const utility::char_t *u_end = *host_begin; - for (;is_user_info_character(*u_end) && u_end != *host_end; u_end++) - { } - - if (*u_end == _XPLATSTR('@')) - { - *host_begin = u_end+1; - *uinfo_begin = authority_begin; - *uinfo_end = u_end; - } - else - { - uinfo_end = uinfo_begin = nullptr; - } - } - } - - // if we see a path character or a slash, then the - // if we see a slash, or any other legal path character, parse the path next - if (*p == _XPLATSTR('/') || is_path_character(*p)) - { - *path_begin = p; - - // the path is delimited by a question-mark (query) or octothorpe (fragment) or by EOS - for (;*p != _XPLATSTR('?') && *p != _XPLATSTR('#') && *p != _XPLATSTR('\0'); p++) - { - if (!is_path_character(*p)) - { - return false; - } - } - *path_end = p; - } - - // if we see a ?, then the query is next - if (*p == _XPLATSTR('?')) - { - // skip over the question mark - p++; - *query_begin = p; - - // the query is delimited by a '#' (fragment) or EOS - for (;*p != _XPLATSTR('#') && *p != _XPLATSTR('\0'); p++) - { - if (!is_query_character(*p)) - { - return false; - } - } - *query_end = p; - } - - // if we see a #, then the fragment is next - if (*p == _XPLATSTR('#')) - { - // skip over the hash mark - p++; - *fragment_begin = p; - - // the fragment is delimited by EOS - for (;*p != _XPLATSTR('\0'); p++) - { - if (!is_fragment_character(*p)) - { - return false; - } - } - *fragment_end = p; - } - - return true; -} - -}}} diff --git a/Release/tests/functional/uri/encoding_tests.cpp b/Release/tests/functional/uri/encoding_tests.cpp index e24cc73462..3daff234f8 100644 --- a/Release/tests/functional/uri/encoding_tests.cpp +++ b/Release/tests/functional/uri/encoding_tests.cpp @@ -33,11 +33,11 @@ TEST(encode_string) TEST(decode_string) { - utility::string_t result = uri::encode_uri(L"first%second\u4e2d\u56fd"); - VERIFY_ARE_EQUAL(L"first%second\u4e2d\u56fd", uri::decode(result)); + utility::string_t result = uri::decode(U("first%25second%E4%B8%AD%E5%9B%BD")); + VERIFY_ARE_EQUAL(L"first%second\u4e2d\u56fd", result); - result = uri::encode_uri(U("first%second")); - VERIFY_ARE_EQUAL(U("first%second"), uri::decode(result)); + result = uri::decode(U("first%25second")); + VERIFY_ARE_EQUAL(U("first%second"), result); } #pragma warning (pop) #endif From a24b81a58bd34e3881fa0a1a37cd366c67b84d9a Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sun, 5 Nov 2017 01:23:52 -0700 Subject: [PATCH 151/438] Fixup static Win32 builds --- Release/src/CMakeLists.txt | 2 +- Release/tests/functional/streams/CMakeLists.txt | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index cfe3dbe760..be53a53305 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -192,7 +192,7 @@ if(WIN32) if (BUILD_SHARED_LIBS) target_compile_definitions(cpprest PRIVATE -D_ASYNCRT_EXPORT -D_PPLX_EXPORT -D_USRDLL) else() - target_compile_definitions(cpprest INTERFACE -D_NO_ASYNCRTIMP -D_NO_PPLXIMP) + target_compile_definitions(cpprest PUBLIC -D_NO_ASYNCRTIMP -D_NO_PPLXIMP) endif() elseif(ANDROID) target_link_libraries(cpprest PRIVATE ${ANDROID_STL_FLAGS}) diff --git a/Release/tests/functional/streams/CMakeLists.txt b/Release/tests/functional/streams/CMakeLists.txt index af45beffca..4b11173b18 100644 --- a/Release/tests/functional/streams/CMakeLists.txt +++ b/Release/tests/functional/streams/CMakeLists.txt @@ -18,5 +18,9 @@ endif() add_casablanca_test(streams_test SOURCES) if(NOT WIN32 OR CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") cpprest_find_boost() - target_link_libraries(streams_test PRIVATE cpprestsdk_boost_internal) + if(NOT TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT") + target_link_libraries(streams_test PRIVATE cpprestsdk_boost_internal) + else() + target_include_directories(streams_test PRIVATE $) + endif() endif() From 9bea093a39b797a204e598189f9fae6f165550fb Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Thu, 9 Nov 2017 09:27:50 +0000 Subject: [PATCH 152/438] Patch to get e.g. "cpprest140d_2_10.dll" as described in Microsoft/cpprestsdk#577 --- Release/src/CMakeLists.txt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index be53a53305..927e98be0f 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -216,8 +216,18 @@ elseif(WINDOWS_STORE) endif() if(WIN32) - set_target_properties(cpprest PROPERTIES - OUTPUT_NAME "cpprest_${CPPREST_VERSION_MAJOR}_${CPPREST_VERSION_MINOR}") + string(SUBSTRING ${CMAKE_VS_PLATFORM_TOOLSET} 1 -1 TOOLSET) + set(CPPREST_VERSION_POSTFIX "_${CPPREST_VERSION_MAJOR}_${CPPREST_VERSION_MINOR}") + foreach(CFG ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${CFG} CFG) + get_target_property(CFG_POSTFIX cpprest ${CFG}_POSTFIX) + if (NOT CFG_POSTFIX) + # forget "NOTFOUND" + set(CFG_POSTFIX) + endif() + set_target_properties(cpprest PROPERTIES + ${CFG}_POSTFIX "${TOOLSET}${CFG_POSTFIX}${CPPREST_VERSION_POSTFIX}") + endforeach() elseif(ANDROID) # Do not use SOVERSION on android. It is completely unsupported (and causes problems). # Perhaps revisit in the future? (NDK r9d, 8/7/14) From 88fd367c8ab38bff2e86ed29550e9dec4b364480 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 9 Nov 2017 12:15:54 -0800 Subject: [PATCH 153/438] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index ae75be9704..79277b4a10 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,6 @@ target_link_libraries(main PRIVATE cpprestsdk::cpprest) * PPL Tasks - A powerful model for composing asynchronous operations based on C++ 11 features * Platforms - Windows desktop, Windows Store, Windows Phone, Ubuntu, OS X, iOS, and Android * Support for Visual Studio 2012, 2013, and 2015 with debugger visualizers -* NuGet package with binaries for Windows and Android platforms ## Contribute Back! From 1a7237d9064ee95a7ce1b83885f0abde46565635 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 9 Nov 2017 12:17:00 -0800 Subject: [PATCH 154/438] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 79277b4a10..89bd7e1ad3 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,8 @@ target_link_libraries(main PRIVATE cpprestsdk::cpprest) * Features - HTTP client/server, JSON, URI, asynchronous streams, WebSockets client, oAuth * PPL Tasks - A powerful model for composing asynchronous operations based on C++ 11 features -* Platforms - Windows desktop, Windows Store, Windows Phone, Ubuntu, OS X, iOS, and Android -* Support for Visual Studio 2012, 2013, and 2015 with debugger visualizers +* Platforms - Windows desktop, Windows Store (UWP), Linux, OS X, Unix, iOS, and Android +* Support for Visual Studio 2015 and 2017 with debugger visualizers ## Contribute Back! From 8120975601997f469d5da6fce3814027c7f6f096 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 13 Nov 2017 23:43:41 -0800 Subject: [PATCH 155/438] Remove use of CMake 3.6 feature: list(FILTER). Fixes #603. --- Release/src/CMakeLists.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index be53a53305..b862e44117 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -11,7 +11,8 @@ source_group("Header Files\\cpprest" FILES ${HEADERS_CPPREST}) source_group("Header Files\\pplx" FILES ${HEADERS_PPLX}) source_group("Header Files\\cpprest\\details" FILES ${HEADERS_DETAILS}) -list(FILTER HEADERS_PPLX EXCLUDE REGEX "threadpool\\.h") +file(GLOB HEADER_PPLX_THREADPOOL "../include/pplx/threadpool.h") +list(REMOVE_ITEM HEADERS_PPLX ${HEADER_PPLX_THREADPOOL}) set(SOURCES ${HEADERS_CPPREST} @@ -163,14 +164,12 @@ endif() if(MSVC) get_target_property(_srcs cpprest SOURCES) - set_source_files_properties(pch/stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") - list(FILTER _srcs EXCLUDE REGEX "pch/stdafx\\.cpp$") - if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") set_property(SOURCE pch/stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") endif() + set_source_files_properties(pch/stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") target_sources(cpprest PRIVATE pch/stdafx.cpp) target_compile_options(cpprest PRIVATE /Yustdafx.h /Zm200) endif() From fc1f692dbeb639c5eff8f31292dc5825f26c787c Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 14 Nov 2017 02:10:39 -0800 Subject: [PATCH 156/438] Remove use of find_dependency(Boost) since it causes problems with CMake versions before 3.9 --- Release/cmake/cpprestsdk-config.in.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Release/cmake/cpprestsdk-config.in.cmake b/Release/cmake/cpprestsdk-config.in.cmake index 39f636c77d..522f8f7db1 100644 --- a/Release/cmake/cpprestsdk-config.in.cmake +++ b/Release/cmake/cpprestsdk-config.in.cmake @@ -7,11 +7,11 @@ if(@CPPREST_USES_OPENSSL@) find_dependency(OpenSSL) endif() -if(@CPPREST_USES_BOOST@) +if(@CPPREST_USES_BOOST@ AND OFF) if(UNIX) find_dependency(Boost COMPONENTS random system thread filesystem chrono atomic date_time regex) else() find_dependency(Boost COMPONENTS system date_time regex) endif() endif() -include("${CMAKE_CURRENT_LIST_DIR}/cpprestsdk-targets.cmake") \ No newline at end of file +include("${CMAKE_CURRENT_LIST_DIR}/cpprestsdk-targets.cmake") From c42a369d179db28baeca76e9037435adb40b6801 Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Tue, 21 Nov 2017 10:33:42 +0000 Subject: [PATCH 157/438] GCC 4.7 in experimental C++11 mode tokenises '<::' at the beginning of a template argument list or *_cast conversion incorrectly as the digraph '<:' (meaning '[') followed by a single ':'; the former can be resolved by -fpermissive, the latter isn't --- Release/CMakeLists.txt | 3 +++ Release/tests/functional/json/parsing_tests.cpp | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 218adcbb34..4f02df386f 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -163,6 +163,9 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") set(LD_FLAGS "${LD_FLAGS} -Wl,-z,defs") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-strict-aliasing") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive") + endif() elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") message("-- Setting msvc options") diff --git a/Release/tests/functional/json/parsing_tests.cpp b/Release/tests/functional/json/parsing_tests.cpp index 2d4925d87a..c1cc7a8305 100644 --- a/Release/tests/functional/json/parsing_tests.cpp +++ b/Release/tests/functional/json/parsing_tests.cpp @@ -223,7 +223,7 @@ TEST(escaping_control_characters) for (int i : chars) { - ::utility::stringstream_t ss; + utility::stringstream_t ss; ss << U("\"\\u") << std::uppercase << std::setfill(U('0')) << std::setw(4) << std::hex << i << U("\""); const auto &str = ss.str(); auto expectedStr = str; @@ -257,8 +257,8 @@ TEST(escaping_control_characters) } // Try constructing a json string value directly. - ::utility::string_t schar; - schar.push_back(static_cast<::utility::string_t::value_type>(i)); + utility::string_t schar; + schar.push_back(static_cast(i)); const auto &sv = json::value::string(schar); VERIFY_ARE_EQUAL(expectedStr, sv.serialize()); From a282292b043e9eca64270b2e50c1071bcc83d2e3 Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Tue, 21 Nov 2017 10:39:16 +0000 Subject: [PATCH 158/438] Workaround for libstdc++ issue with GCC 4.7 (ultimately fixed in GCC 4.9) that means std::this_thread::yield() and std::this_thread::sleep_for() are only conditionally provided; see https://stackoverflow.com/a/12961816 --- Release/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 4f02df386f..86a1a8475e 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -164,7 +164,7 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-strict-aliasing") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -D_GLIBCXX_USE_SCHED_YIELD -D_GLIBCXX_USE_NANOSLEEP") endif() elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") From 7ee017664c8a8280ae7e835aa0ded9c47e858e19 Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Tue, 21 Nov 2017 10:41:12 +0000 Subject: [PATCH 159/438] At GCC 4.7, libstdc++ std::map didn't provide emplace(); using insert() is insignificant here --- Release/tests/common/TestRunner/test_runner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Release/tests/common/TestRunner/test_runner.cpp b/Release/tests/common/TestRunner/test_runner.cpp index bb5160d4d9..7ec573dbbd 100644 --- a/Release/tests/common/TestRunner/test_runner.cpp +++ b/Release/tests/common/TestRunner/test_runner.cpp @@ -409,7 +409,7 @@ testlist_t load_all_tests(test_module_loader& module_loader) testlist_t testlists; // Retrieve the static tests and clear for dll loading. - testlists.emplace("", UnitTest::GetTestList()); + testlists.insert({ "", UnitTest::GetTestList() }); UnitTest::GetTestList().Clear(); // Cycle through all the test binaries and load them @@ -445,7 +445,7 @@ testlist_t load_all_tests(test_module_loader& module_loader) std::cout << "Loaded " << binary << "..." << std::endl; // Store the loaded binary into the test list map - testlists.emplace(binary, UnitTest::GetTestList()); + testlists.insert({ binary, UnitTest::GetTestList() }); UnitTest::GetTestList().Clear(); } } From 43a6f73cfe44b1954f5e5052e06ca96dba9f1707 Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Tue, 21 Nov 2017 10:45:51 +0000 Subject: [PATCH 160/438] At GCC 4.7, C++11 rules for noexcept specification of implicit destructors (and default specification on explicit destructors without exception specifications) aren't perfectly implemented --- Release/src/websockets/client/ws_client_wspp.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index e9e7658b18..dd1f809f6d 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -127,7 +127,7 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: #endif {} - ~wspp_callback_client() + ~wspp_callback_client() CPPREST_NOEXCEPT { _ASSERTE(m_state < DESTROYED); std::unique_lock lock(m_wspp_client_lock); @@ -730,6 +730,7 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: }; struct websocketpp_client : websocketpp_client_base { + ~websocketpp_client() CPPREST_NOEXCEPT {} websocketpp::client & non_tls_client() override { return m_client; @@ -739,6 +740,7 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: }; struct websocketpp_tls_client : websocketpp_client_base { + ~websocketpp_tls_client() CPPREST_NOEXCEPT {} websocketpp::client & tls_client() override { return m_client; From 5244af7ccf165709ec26c558dfcdb2531e0415cd Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Tue, 21 Nov 2017 12:42:42 +0000 Subject: [PATCH 161/438] =?UTF-8?q?At=20GCC=204.7,=20there=20are=20several?= =?UTF-8?q?=20bugs=20that=20cause=20"error:=20=E2=80=98this=E2=80=99=20was?= =?UTF-8?q?=20not=20captured=20for=20this=20lambda=20function"=20to=20be?= =?UTF-8?q?=20reported=20incorrectly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Release/src/http/client/http_client_asio.cpp | 28 +++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 19e09b2427..dc0e5daad3 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -44,6 +44,16 @@ #include #include +#if !defined(__GNUC__) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) +#define AND_CAPTURE_MEMBER_FUNCTION_POINTERS +#else +// GCC Bug 56222 - Pointer to member in lambda should not require this to be captured +// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56222 +// GCC Bug 51494 - Legal program rejection - capturing "this" when using static method inside lambda +// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51494 +#define AND_CAPTURE_MEMBER_FUNCTION_POINTERS , this +#endif + using boost::asio::ip::tcp; #ifdef __ANDROID__ @@ -620,7 +630,7 @@ class asio_context : public request_context, public std::enable_shared_from_this proxy_host = utility::conversions::to_utf8string(proxy_uri.host()); } - auto start_http_request_flow = [proxy_type, proxy_host, proxy_port](std::shared_ptr ctx) + auto start_http_request_flow = [proxy_type, proxy_host, proxy_port AND_CAPTURE_MEMBER_FUNCTION_POINTERS](std::shared_ptr ctx) { if (ctx->m_request._cancellation_token().is_canceled()) { @@ -1010,7 +1020,7 @@ class asio_context : public request_context, public std::enable_shared_from_this auto readbuf = _get_readbuffer(); uint8_t *buf = boost::asio::buffer_cast(m_body_buf.prepare(chunkSize + http::details::chunked_encoding::additional_encoding_space)); const auto this_request = shared_from_this(); - readbuf.getn(buf + http::details::chunked_encoding::data_offset, chunkSize).then([this_request, buf, chunkSize](pplx::task op) + readbuf.getn(buf + http::details::chunked_encoding::data_offset, chunkSize).then([this_request, buf, chunkSize AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { size_t readSize = 0; try @@ -1067,7 +1077,7 @@ class asio_context : public request_context, public std::enable_shared_from_this const auto this_request = shared_from_this(); const auto readSize = static_cast(std::min(static_cast(m_http_client->client_config().chunksize()), m_content_length - m_uploaded)); auto readbuf = _get_readbuffer(); - readbuf.getn(boost::asio::buffer_cast(m_body_buf.prepare(readSize)), readSize).then([this_request](pplx::task op) + readbuf.getn(boost::asio::buffer_cast(m_body_buf.prepare(readSize)), readSize).then([this_request AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { try { @@ -1370,7 +1380,7 @@ class asio_context : public request_context, public std::enable_shared_from_this auto shared_decompressed = std::make_shared(std::move(decompressed)); writeBuffer.putn_nocopy(shared_decompressed->data(), shared_decompressed->size()) - .then([this_request, to_read, shared_decompressed](pplx::task op) + .then([this_request, to_read, shared_decompressed AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { try { @@ -1388,7 +1398,7 @@ class asio_context : public request_context, public std::enable_shared_from_this } else { - writeBuffer.putn_nocopy(boost::asio::buffer_cast(m_body_buf.data()), to_read).then([this_request, to_read](pplx::task op) + writeBuffer.putn_nocopy(boost::asio::buffer_cast(m_body_buf.data()), to_read).then([this_request, to_read AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { try { @@ -1485,7 +1495,7 @@ class asio_context : public request_context, public std::enable_shared_from_this auto shared_decompressed = std::make_shared(std::move(decompressed)); writeBuffer.putn_nocopy(shared_decompressed->data(), shared_decompressed->size()) - .then([this_request, read_size, shared_decompressed](pplx::task op) + .then([this_request, read_size, shared_decompressed AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { size_t writtenSize = 0; try @@ -1507,7 +1517,7 @@ class asio_context : public request_context, public std::enable_shared_from_this else { writeBuffer.putn_nocopy(boost::asio::buffer_cast(m_body_buf.data()), read_size) - .then([this_request](pplx::task op) + .then([this_request AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { size_t writtenSize = 0; try @@ -1558,7 +1568,7 @@ class asio_context : public request_context, public std::enable_shared_from_this m_timer.expires_from_now(m_duration); auto ctx = m_ctx; - m_timer.async_wait([ctx](const boost::system::error_code& ec) + m_timer.async_wait([ctx AND_CAPTURE_MEMBER_FUNCTION_POINTERS](const boost::system::error_code& ec) { handle_timeout(ec, ctx); }); @@ -1573,7 +1583,7 @@ class asio_context : public request_context, public std::enable_shared_from_this // The existing handler was canceled so schedule a new one. assert(m_state == started); auto ctx = m_ctx; - m_timer.async_wait([ctx](const boost::system::error_code& ec) + m_timer.async_wait([ctx AND_CAPTURE_MEMBER_FUNCTION_POINTERS](const boost::system::error_code& ec) { handle_timeout(ec, ctx); }); From ca81f1f80e84777efe74c83777bfdd365f6597df Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 21 Nov 2017 20:19:26 -0800 Subject: [PATCH 162/438] Complete removal of uri_parser --- Release/src/build/common.vcxitems | 2 -- Release/src/build/common.vcxitems.filters | 6 ------ 2 files changed, 8 deletions(-) diff --git a/Release/src/build/common.vcxitems b/Release/src/build/common.vcxitems index 4abeacb737..520e0dbac3 100644 --- a/Release/src/build/common.vcxitems +++ b/Release/src/build/common.vcxitems @@ -34,7 +34,6 @@ - @@ -58,7 +57,6 @@ - diff --git a/Release/src/build/common.vcxitems.filters b/Release/src/build/common.vcxitems.filters index 8839f755df..5445979e22 100644 --- a/Release/src/build/common.vcxitems.filters +++ b/Release/src/build/common.vcxitems.filters @@ -52,9 +52,6 @@ Source Files - - Source Files - Source Files @@ -173,9 +170,6 @@ Header Files\cpprest\details - - Header Files\cpprest\details - Header Files\cpprest\details From fe308d9fe3b4928ccd293b527fa4f097c09a1a72 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 21 Nov 2017 20:54:40 -0800 Subject: [PATCH 163/438] Fix for #595 --- Release/src/uri/uri.cpp | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/Release/src/uri/uri.cpp b/Release/src/uri/uri.cpp index f257787e94..4c06e52e2b 100644 --- a/Release/src/uri/uri.cpp +++ b/Release/src/uri/uri.cpp @@ -106,20 +106,6 @@ namespace return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == ':'; } - /// - /// Legal characters in the host portion include: - /// - Any unreserved character - /// - The percent character ('%'), and thus any percent-endcoded octet - /// - The sub-delimiters - /// - ':' (colon) - /// - '[' (open bracket) - /// - ']' (close bracket) - /// - inline bool is_host_character(int c) - { - return is_unreserved(c) || is_sub_delim(c) || c == '%' || c == ':' || c == '[' || c == ']'; - } - /// /// Legal characters in the authority portion include: /// - Any unreserved character @@ -653,19 +639,20 @@ static int hex_char_digit_to_decimal_char(int hex) return decimal; } -utility::string_t uri::decode(const utility::string_t &encoded) +template +static std::string decode_template(const String& encoded) { - utf8string raw; - for(auto iter = encoded.begin(); iter != encoded.end(); ++iter) + std::string raw; + for (auto iter = encoded.begin(); iter != encoded.end(); ++iter) { - if(*iter == _XPLATSTR('%')) + if (*iter == '%') { - if(++iter == encoded.end()) + if (++iter == encoded.end()) { throw uri_exception("Invalid URI string, two hexadecimal digits must follow '%'"); } int decimal_value = hex_char_digit_to_decimal_char(static_cast(*iter)) << 4; - if(++iter == encoded.end()) + if (++iter == encoded.end()) { throw uri_exception("Invalid URI string, two hexadecimal digits must follow '%'"); } @@ -673,7 +660,7 @@ utility::string_t uri::decode(const utility::string_t &encoded) raw.push_back(static_cast(decimal_value)); } - else if (*iter > CHAR_MAX || *iter < 0) + else if (*iter > 127 || *iter < 0) { throw uri_exception("Invalid encoded URI string, must be entirely ascii"); } @@ -683,7 +670,12 @@ utility::string_t uri::decode(const utility::string_t &encoded) raw.push_back(static_cast(*iter)); } } - return to_string_t(raw); + return raw; +} + +utility::string_t uri::decode(const utility::string_t &encoded) +{ + return to_string_t(decode_template(encoded)); } std::vector uri::split_path(const utility::string_t &path) From 307c447367377d9b13752d32118f6778833d7978 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 21 Nov 2017 21:13:41 -0800 Subject: [PATCH 164/438] Fix outside_tests:ignore_server_cert_invalid --- Release/tests/functional/http/client/outside_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/tests/functional/http/client/outside_tests.cpp b/Release/tests/functional/http/client/outside_tests.cpp index 56825fa00d..4c16fb4db6 100644 --- a/Release/tests/functional/http/client/outside_tests.cpp +++ b/Release/tests/functional/http/client/outside_tests.cpp @@ -198,7 +198,7 @@ TEST(ignore_server_cert_invalid, http_client_config config; config.set_validate_certificates(false); config.set_timeout(std::chrono::seconds(1)); - http_client client(U("https://www.pcwebshop.co.uk/"), config); + http_client client(U("https://expired.badssl.com/"), config); auto request = client.request(methods::GET).get(); VERIFY_ARE_EQUAL(status_codes::OK, request.status_code()); From d0ce63e06422bd5eaa85cffb3aa39629c67ce4d9 Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Thu, 23 Nov 2017 17:03:51 +0000 Subject: [PATCH 165/438] VS2013 incorrectly reports "warning C4573: the usage of 'symbol' requires the compiler to capture 'this' but the current default capture mode does not allow it"; the issue and workaround is the same as for GCC 4.7 in commit:5244af7c. --- Release/src/http/client/http_client_asio.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index dc0e5daad3..36e3b10362 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -44,7 +44,9 @@ #include #include -#if !defined(__GNUC__) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) +#if defined(__GNUC__) + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) #define AND_CAPTURE_MEMBER_FUNCTION_POINTERS #else // GCC Bug 56222 - Pointer to member in lambda should not require this to be captured @@ -54,6 +56,21 @@ #define AND_CAPTURE_MEMBER_FUNCTION_POINTERS , this #endif +#elif defined(_MSC_VER) + +#if _MSC_VER >= 1900 +#define AND_CAPTURE_MEMBER_FUNCTION_POINTERS +#else +// This bug also afflicts VS2013 which incorrectly reports "warning C4573: the usage of 'symbol' requires the compiler to capture 'this' but the current default capture mode does not allow it" +#define AND_CAPTURE_MEMBER_FUNCTION_POINTERS , this +#endif + +#else + +#define AND_CAPTURE_MEMBER_FUNCTION_POINTERS + +#endif + using boost::asio::ip::tcp; #ifdef __ANDROID__ From b226326a1df1e0404686cd59e9b8546cf54382cc Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Thu, 23 Nov 2017 17:12:55 +0000 Subject: [PATCH 166/438] Define http_listener if CPPREST_FORCE_HTTP_LISTENER_ASIO is defined --- Release/include/cpprest/http_listener.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/include/cpprest/http_listener.h b/Release/include/cpprest/http_listener.h index 3c154e49a6..88faa97da1 100644 --- a/Release/include/cpprest/http_listener.h +++ b/Release/include/cpprest/http_listener.h @@ -21,7 +21,7 @@ #include #endif -#if !defined(_WIN32) || (_WIN32_WINNT >= _WIN32_WINNT_VISTA && !defined(__cplusplus_winrt)) +#if !defined(_WIN32) || (_WIN32_WINNT >= _WIN32_WINNT_VISTA && !defined(__cplusplus_winrt)) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) namespace web { From 823f3b737127bf23bb97fd42ab3aad3ec7cc994f Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Fri, 24 Nov 2017 17:45:16 +0000 Subject: [PATCH 167/438] Define http_listener_impl and http_server_api if CPPREST_FORCE_HTTP_LISTENER_ASIO is defined --- Release/src/http/listener/http_listener.cpp | 2 +- Release/src/http/listener/http_server_api.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Release/src/http/listener/http_listener.cpp b/Release/src/http/listener/http_listener.cpp index 704e17c475..baa204b56d 100644 --- a/Release/src/http/listener/http_listener.cpp +++ b/Release/src/http/listener/http_listener.cpp @@ -13,7 +13,7 @@ #include "stdafx.h" -#if !defined(_WIN32) || (_WIN32_WINNT >= _WIN32_WINNT_VISTA && !defined(__cplusplus_winrt)) +#if !defined(_WIN32) || (_WIN32_WINNT >= _WIN32_WINNT_VISTA && !defined(__cplusplus_winrt)) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) using namespace web::http::experimental; diff --git a/Release/src/http/listener/http_server_api.cpp b/Release/src/http/listener/http_server_api.cpp index b72d6cf8ef..9a8289b7fa 100644 --- a/Release/src/http/listener/http_server_api.cpp +++ b/Release/src/http/listener/http_server_api.cpp @@ -11,7 +11,7 @@ #include "stdafx.h" -#if !defined(_WIN32) || (_WIN32_WINNT >= _WIN32_WINNT_VISTA && !defined(__cplusplus_winrt)) +#if !defined(_WIN32) || (_WIN32_WINNT >= _WIN32_WINNT_VISTA && !defined(__cplusplus_winrt)) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) #include "http_server_impl.h" using namespace web; From ff50bb0305ba6495ffc1d4170f4c2eec88404700 Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Fri, 24 Nov 2017 17:41:57 +0000 Subject: [PATCH 168/438] Suppress two instances of "warning C4503: 'identifier' : decorated name length exceeded, name was truncated" generated too late for disable to be effective inside push/pop --- .../functional/websockets/utilities/test_websocket_server.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Release/tests/functional/websockets/utilities/test_websocket_server.cpp b/Release/tests/functional/websockets/utilities/test_websocket_server.cpp index 108b0455cc..b4cfd806c4 100644 --- a/Release/tests/functional/websockets/utilities/test_websocket_server.cpp +++ b/Release/tests/functional/websockets/utilities/test_websocket_server.cpp @@ -18,8 +18,9 @@ #include "test_websocket_server.h" #ifdef _WIN32 +#pragma warning(disable : 4503) // generated too late for disable to be effective inside push/pop #pragma warning( push ) -#pragma warning(disable : 4100 4127 4996 4512 4701 4267 4067 4503 4005) +#pragma warning(disable : 4100 4127 4996 4512 4701 4267 4067 4005) #define _WEBSOCKETPP_CPP11_STL_ #define _WEBSOCKETPP_CONSTEXPR_TOKEN_ #if _MSC_VER < 1900 From c2f2388479779f64f34652871fbdf93fa4b0b58b Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Fri, 24 Nov 2017 17:50:29 +0000 Subject: [PATCH 169/438] Enable test create_https_listener_get on Windows if CPPREST_FORCE_HTTP_LISTENER_ASIO is defined --- .../functional/http/listener/listener_construction_tests.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Release/tests/functional/http/listener/listener_construction_tests.cpp b/Release/tests/functional/http/listener/listener_construction_tests.cpp index 1637160bc0..1bf31ffa88 100644 --- a/Release/tests/functional/http/listener/listener_construction_tests.cpp +++ b/Release/tests/functional/http/listener/listener_construction_tests.cpp @@ -430,7 +430,7 @@ TEST_FIXTURE(uri_address, listener_config_creation) } } -#if !defined(_WIN32) && !defined(__cplusplus_winrt) +#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) TEST_FIXTURE(uri_address, create_https_listener_get, "Ignore", "github 209") { @@ -545,7 +545,6 @@ XzJTD4slrGSJrcpLt/g/Jqqdjg== for (auto&& h : all_headers) { - std::cout << "HEADER - " << h.first << ": " << h.second << std::endl; VERIFY_IS_TRUE(request.headers().has(h.first)); VERIFY_ARE_EQUAL(h.second, request.headers().find(h.first)->second); } From 0f658589ad8a39152dc15c03eda06bbc878343d9 Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Fri, 24 Nov 2017 17:57:39 +0000 Subject: [PATCH 170/438] VS2013 incorrectly reports "warning C4573: the usage of 'symbol' requires the compiler to capture 'this' but the current default capture mode does not allow it"; the issue and workaround is the same as for GCC 4.7 in commit:5244af7c. (cherry picked from commit d0ce63e06422bd5eaa85cffb3aa39629c67ce4d9) --- Release/src/http/client/http_client_asio.cpp | 45 ++++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 19e09b2427..36e3b10362 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -44,6 +44,33 @@ #include #include +#if defined(__GNUC__) + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) +#define AND_CAPTURE_MEMBER_FUNCTION_POINTERS +#else +// GCC Bug 56222 - Pointer to member in lambda should not require this to be captured +// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56222 +// GCC Bug 51494 - Legal program rejection - capturing "this" when using static method inside lambda +// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51494 +#define AND_CAPTURE_MEMBER_FUNCTION_POINTERS , this +#endif + +#elif defined(_MSC_VER) + +#if _MSC_VER >= 1900 +#define AND_CAPTURE_MEMBER_FUNCTION_POINTERS +#else +// This bug also afflicts VS2013 which incorrectly reports "warning C4573: the usage of 'symbol' requires the compiler to capture 'this' but the current default capture mode does not allow it" +#define AND_CAPTURE_MEMBER_FUNCTION_POINTERS , this +#endif + +#else + +#define AND_CAPTURE_MEMBER_FUNCTION_POINTERS + +#endif + using boost::asio::ip::tcp; #ifdef __ANDROID__ @@ -620,7 +647,7 @@ class asio_context : public request_context, public std::enable_shared_from_this proxy_host = utility::conversions::to_utf8string(proxy_uri.host()); } - auto start_http_request_flow = [proxy_type, proxy_host, proxy_port](std::shared_ptr ctx) + auto start_http_request_flow = [proxy_type, proxy_host, proxy_port AND_CAPTURE_MEMBER_FUNCTION_POINTERS](std::shared_ptr ctx) { if (ctx->m_request._cancellation_token().is_canceled()) { @@ -1010,7 +1037,7 @@ class asio_context : public request_context, public std::enable_shared_from_this auto readbuf = _get_readbuffer(); uint8_t *buf = boost::asio::buffer_cast(m_body_buf.prepare(chunkSize + http::details::chunked_encoding::additional_encoding_space)); const auto this_request = shared_from_this(); - readbuf.getn(buf + http::details::chunked_encoding::data_offset, chunkSize).then([this_request, buf, chunkSize](pplx::task op) + readbuf.getn(buf + http::details::chunked_encoding::data_offset, chunkSize).then([this_request, buf, chunkSize AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { size_t readSize = 0; try @@ -1067,7 +1094,7 @@ class asio_context : public request_context, public std::enable_shared_from_this const auto this_request = shared_from_this(); const auto readSize = static_cast(std::min(static_cast(m_http_client->client_config().chunksize()), m_content_length - m_uploaded)); auto readbuf = _get_readbuffer(); - readbuf.getn(boost::asio::buffer_cast(m_body_buf.prepare(readSize)), readSize).then([this_request](pplx::task op) + readbuf.getn(boost::asio::buffer_cast(m_body_buf.prepare(readSize)), readSize).then([this_request AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { try { @@ -1370,7 +1397,7 @@ class asio_context : public request_context, public std::enable_shared_from_this auto shared_decompressed = std::make_shared(std::move(decompressed)); writeBuffer.putn_nocopy(shared_decompressed->data(), shared_decompressed->size()) - .then([this_request, to_read, shared_decompressed](pplx::task op) + .then([this_request, to_read, shared_decompressed AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { try { @@ -1388,7 +1415,7 @@ class asio_context : public request_context, public std::enable_shared_from_this } else { - writeBuffer.putn_nocopy(boost::asio::buffer_cast(m_body_buf.data()), to_read).then([this_request, to_read](pplx::task op) + writeBuffer.putn_nocopy(boost::asio::buffer_cast(m_body_buf.data()), to_read).then([this_request, to_read AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { try { @@ -1485,7 +1512,7 @@ class asio_context : public request_context, public std::enable_shared_from_this auto shared_decompressed = std::make_shared(std::move(decompressed)); writeBuffer.putn_nocopy(shared_decompressed->data(), shared_decompressed->size()) - .then([this_request, read_size, shared_decompressed](pplx::task op) + .then([this_request, read_size, shared_decompressed AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { size_t writtenSize = 0; try @@ -1507,7 +1534,7 @@ class asio_context : public request_context, public std::enable_shared_from_this else { writeBuffer.putn_nocopy(boost::asio::buffer_cast(m_body_buf.data()), read_size) - .then([this_request](pplx::task op) + .then([this_request AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { size_t writtenSize = 0; try @@ -1558,7 +1585,7 @@ class asio_context : public request_context, public std::enable_shared_from_this m_timer.expires_from_now(m_duration); auto ctx = m_ctx; - m_timer.async_wait([ctx](const boost::system::error_code& ec) + m_timer.async_wait([ctx AND_CAPTURE_MEMBER_FUNCTION_POINTERS](const boost::system::error_code& ec) { handle_timeout(ec, ctx); }); @@ -1573,7 +1600,7 @@ class asio_context : public request_context, public std::enable_shared_from_this // The existing handler was canceled so schedule a new one. assert(m_state == started); auto ctx = m_ctx; - m_timer.async_wait([ctx](const boost::system::error_code& ec) + m_timer.async_wait([ctx AND_CAPTURE_MEMBER_FUNCTION_POINTERS](const boost::system::error_code& ec) { handle_timeout(ec, ctx); }); From 38bf3f3ae53956a33860c67ea217d4a3c9b5a7e1 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 29 Nov 2017 12:05:09 -0800 Subject: [PATCH 171/438] Update README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 89bd7e1ad3..f084f87e9f 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,13 @@ The C++ REST SDK is a Microsoft project for cloud-based client-server communicat ## Getting Started +[![Vcpkg package](https://repology.org/badge/version-for-repo/vcpkg/cpprestsdk.svg)](https://repology.org/metapackage/cpprestsdk) +[![Homebrew package](https://repology.org/badge/version-for-repo/homebrew/cpprestsdk.svg)](https://repology.org/metapackage/cpprestsdk) +[![Ubuntu 18.04 package](https://repology.org/badge/version-for-repo/ubuntu_18_04/casablanca.svg)](https://repology.org/metapackage/casablanca) +[![Fedora Rawhide package](https://repology.org/badge/version-for-repo/fedora_rawhide/cpprest.svg)](https://repology.org/metapackage/cpprest) +[![openSUSE Tumbleweed package](https://repology.org/badge/version-for-repo/opensuse_tumbleweed/cpprest.svg)](https://repology.org/metapackage/cpprest) +[![Debian Testing package](https://repology.org/badge/version-for-repo/debian_testing/casablanca.svg)](https://repology.org/metapackage/casablanca) + With [vcpkg](https://github.com/Microsoft/vcpkg) on Windows ``` PS> vcpkg install cpprestsdk cpprestsdk:x64-windows From ece8108832a6ae6f6b64105c44f59c7fbb90bfd6 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 30 Nov 2017 15:27:46 -0800 Subject: [PATCH 172/438] Prevent automatic instantiation of Concurrency::Details::_do_while() --- Release/include/cpprest/astreambuf.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Release/include/cpprest/astreambuf.h b/Release/include/cpprest/astreambuf.h index cca1abc9cb..c0463835b2 100644 --- a/Release/include/cpprest/astreambuf.h +++ b/Release/include/cpprest/astreambuf.h @@ -26,13 +26,13 @@ namespace Concurrency { namespace details { - template - pplx::task _do_while(std::function(void)> func) + template + pplx::task _do_while(F func) { - pplx::task first = func(); - return first.then([=](bool guard) -> pplx::task { + pplx::task first = func(); + return first.then([=](bool guard) -> pplx::task { if (guard) - return Concurrency::details::_do_while(func); + return Concurrency::details::_do_while(func); else return first; }); @@ -1200,3 +1200,4 @@ namespace streams }; }} + From 91a666b9e76e51b227e44e9db6c371a19f7d2fcb Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Fri, 1 Dec 2017 13:59:23 -0800 Subject: [PATCH 173/438] Update badges --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f084f87e9f..4669fd8871 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,12 @@ The C++ REST SDK is a Microsoft project for cloud-based client-server communicat ## Getting Started -[![Vcpkg package](https://repology.org/badge/version-for-repo/vcpkg/cpprestsdk.svg)](https://repology.org/metapackage/cpprestsdk) -[![Homebrew package](https://repology.org/badge/version-for-repo/homebrew/cpprestsdk.svg)](https://repology.org/metapackage/cpprestsdk) -[![Ubuntu 18.04 package](https://repology.org/badge/version-for-repo/ubuntu_18_04/casablanca.svg)](https://repology.org/metapackage/casablanca) -[![Fedora Rawhide package](https://repology.org/badge/version-for-repo/fedora_rawhide/cpprest.svg)](https://repology.org/metapackage/cpprest) -[![openSUSE Tumbleweed package](https://repology.org/badge/version-for-repo/opensuse_tumbleweed/cpprest.svg)](https://repology.org/metapackage/cpprest) -[![Debian Testing package](https://repology.org/badge/version-for-repo/debian_testing/casablanca.svg)](https://repology.org/metapackage/casablanca) +[![Vcpkg package](https://repology.org/badge/version-for-repo/vcpkg/cpprestsdk.svg)](https://repology.org/metapackage/cpprestsdk)
+[![Homebrew package](https://repology.org/badge/version-for-repo/homebrew/cpprestsdk.svg)](https://repology.org/metapackage/cpprestsdk)
+[![Ubuntu 18.04 package](https://repology.org/badge/version-for-repo/ubuntu_18_04/cpprestsdk.svg)](https://repology.org/metapackage/cpprestsdk)
+[![Fedora Rawhide package](https://repology.org/badge/version-for-repo/fedora_rawhide/cpprestsdk.svg)](https://repology.org/metapackage/cpprestsdk)
+[![openSUSE Tumbleweed package](https://repology.org/badge/version-for-repo/opensuse_tumbleweed/cpprestsdk.svg)](https://repology.org/metapackage/cpprestsdk)
+[![Debian Testing package](https://repology.org/badge/version-for-repo/debian_testing/cpprestsdk.svg)](https://repology.org/metapackage/cpprestsdk)
With [vcpkg](https://github.com/Microsoft/vcpkg) on Windows ``` From 09d5984e022d36295e1afa276d6923b1d579f67e Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 2 Dec 2017 15:50:36 -0800 Subject: [PATCH 174/438] Improve MSVC compiler throughput by avoiding unneeded instantiations --- Release/include/cpprest/astreambuf.h | 1 + Release/include/pplx/pplxtasks.h | 72 ++++++++-------------------- 2 files changed, 20 insertions(+), 53 deletions(-) diff --git a/Release/include/cpprest/astreambuf.h b/Release/include/cpprest/astreambuf.h index c0463835b2..642f0738dd 100644 --- a/Release/include/cpprest/astreambuf.h +++ b/Release/include/cpprest/astreambuf.h @@ -1200,4 +1200,5 @@ namespace streams }; }} + diff --git a/Release/include/pplx/pplxtasks.h b/Release/include/pplx/pplxtasks.h index c3f9552e35..212c6ba4cc 100644 --- a/Release/include/pplx/pplxtasks.h +++ b/Release/include/pplx/pplxtasks.h @@ -60,6 +60,7 @@ void cpprest_init(JavaVM*); #include #if defined(_MSC_VER) +#include #if defined(__cplusplus_winrt) #include #include @@ -6698,7 +6699,7 @@ auto when_all(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions /// /**/ template -task> operator&&(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs) +auto operator&&(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs) { task<_ReturnType> _PTasks[2] = {_Lhs, _Rhs}; return when_all(_PTasks, _PTasks+2); @@ -6730,7 +6731,7 @@ task> operator&&(const task<_ReturnType> & _Lhs, const /// /**/ template -task> operator&&(const task> & _Lhs, const task<_ReturnType> & _Rhs) +auto operator&&(const task> & _Lhs, const task<_ReturnType> & _Rhs) { return details::_WhenAllVectorAndValue(_Lhs, _Rhs, true); } @@ -6761,7 +6762,7 @@ task> operator&&(const task> & /// /**/ template -task> operator&&(const task<_ReturnType> & _Lhs, const task> & _Rhs) +auto operator&&(const task<_ReturnType> & _Lhs, const task> & _Rhs) { return details::_WhenAllVectorAndValue(_Rhs, _Lhs, false); } @@ -6792,43 +6793,12 @@ task> operator&&(const task<_ReturnType> & _Lhs, const /// /**/ template -task> operator&&(const task> & _Lhs, const task> & _Rhs) +auto operator&&(const task> & _Lhs, const task> & _Rhs) { task> _PTasks[2] = {_Lhs, _Rhs}; return when_all(_PTasks, _PTasks+2); } -/// -/// Creates a task that will complete succesfully when both of the tasks supplied as arguments complete successfully. -/// -/// -/// The type of the returned task. -/// -/// -/// The first task to combine into the resulting task. -/// -/// -/// The second task to combine into the resulting task. -/// -/// -/// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type T, -/// the output of this function will be a task<std::vector<T>>. If the input tasks are of type void the output -/// task will also be a task<void>. -/// To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator -/// produces a task<std::vector<T>> if either one or both of the tasks are of type task<std::vector<T>>. -/// -/// -/// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception, -/// if one is encoutered, will be thrown if you call get() or wait() on that task. -/// -/// -/**/ -inline task operator&&(const task & _Lhs, const task & _Rhs) -{ - task _PTasks[2] = {_Lhs, _Rhs}; - return when_all(_PTasks, _PTasks+2); -} - namespace details { // Helper struct for when_any operators to know when tasks have completed @@ -7114,7 +7084,7 @@ auto when_any(_Iterator _Begin, _Iterator _End, cancellation_token _Cancellation /// /**/ template -task<_ReturnType> operator||(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs) +auto operator||(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs) { auto _PParam = new details::_RunAnyParam>(); @@ -7175,7 +7145,7 @@ task<_ReturnType> operator||(const task<_ReturnType> & _Lhs, const task<_ReturnT /// /**/ template -task> operator||(const task> & _Lhs, const task<_ReturnType> & _Rhs) +auto operator||(const task> & _Lhs, const task<_ReturnType> & _Rhs) { auto _PParam = new details::_RunAnyParam, details::_CancellationTokenState *>>(); @@ -7249,7 +7219,7 @@ task> operator||(const task> & /// /**/ template -task> operator||(const task<_ReturnType> & _Lhs, const task> & _Rhs) +auto operator||(const task<_ReturnType> & _Lhs, const task> & _Rhs) { return _Rhs || _Lhs; } @@ -7280,14 +7250,17 @@ task> operator||(const task<_ReturnType> & _Lhs, const /// /// /**/ -inline task operator||(const task & _Lhs, const task & _Rhs) +template, typename _Pair = std::pair> +_Ty operator||(const task & _Lhs_arg, const task & _Rhs_arg) { - auto _PParam = new details::_RunAnyParam>(); + const _Ty& _Lhs = _Lhs_arg; + const _Ty& _Rhs = _Rhs_arg; + auto _PParam = new details::_RunAnyParam<_Pair>(); task> _Any_task_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token()); // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called, // So that _PParam can be used before it getting deleted. - auto _ReturnTask = _Any_task_completed._Then([=](std::pair _Ret) { + auto _ReturnTask = _Any_task_completed._Then([=](_Pair _Ret) { _ASSERTE(_Ret.second); details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second); }, nullptr); @@ -7298,7 +7271,7 @@ inline task operator||(const task & _Lhs, const task & _Rhs) } _PParam->_M_numTasks = 2; - auto _Continuation = [_PParam](task _ResultTask) mutable { + auto _Continuation = [_PParam](_Ty _ResultTask) mutable { // Dev10 compiler needs this. auto _PParam1 = _PParam; auto _Func = [&_ResultTask, _PParam1]() { @@ -7321,18 +7294,10 @@ task<_Ty> task_from_result(_Ty _Param, const task_options& _TaskOptions = task_o return create_task(_Tce, _TaskOptions); } -// Work around VS 2010 compiler bug -#if _MSC_VER == 1600 -inline task task_from_result(bool _Param) -{ - task_completion_event _Tce; - _Tce.set(_Param); - return create_task(_Tce, task_options()); -} -#endif -inline task task_from_result(const task_options& _TaskOptions = task_options()) +template +inline task<_Ty> task_from_result(const task_options& _TaskOptions = task_options()) { - task_completion_event _Tce; + task_completion_event<_Ty> _Tce; _Tce.set(); return create_task(_Tce, _TaskOptions); } @@ -7367,3 +7332,4 @@ namespace concurrency = Concurrency; #endif #endif // _PPLXTASKS_H + From b855c0abc7586103bef33e4e533a9f1ce8c7c3d4 Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Tue, 5 Dec 2017 12:01:29 +0000 Subject: [PATCH 175/438] Add http_listener configuration for the backlog, the maximum length of the queue of pending connections on the port. --- Release/include/cpprest/http_listener.h | 26 +++++++++++++++++++ .../src/http/listener/http_server_asio.cpp | 11 +++++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/Release/include/cpprest/http_listener.h b/Release/include/cpprest/http_listener.h index 3c154e49a6..d51e6e512f 100644 --- a/Release/include/cpprest/http_listener.h +++ b/Release/include/cpprest/http_listener.h @@ -46,6 +46,7 @@ class http_listener_config ///
http_listener_config() : m_timeout(utility::seconds(120)) + , m_backlog(0) {} ///
@@ -54,6 +55,7 @@ class http_listener_config /// http_listener_config to copy. http_listener_config(const http_listener_config &other) : m_timeout(other.m_timeout) + , m_backlog(other.m_backlog) #if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) , m_ssl_context_callback(other.m_ssl_context_callback) #endif @@ -65,6 +67,7 @@ class http_listener_config /// http_listener_config to move from. http_listener_config(http_listener_config &&other) : m_timeout(std::move(other.m_timeout)) + , m_backlog(std::move(other.m_backlog)) #if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) , m_ssl_context_callback(std::move(other.m_ssl_context_callback)) #endif @@ -79,6 +82,7 @@ class http_listener_config if(this != &rhs) { m_timeout = rhs.m_timeout; + m_backlog = rhs.m_backlog; #if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) m_ssl_context_callback = rhs.m_ssl_context_callback; #endif @@ -95,6 +99,7 @@ class http_listener_config if(this != &rhs) { m_timeout = std::move(rhs.m_timeout); + m_backlog = std::move(rhs.m_backlog); #if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) m_ssl_context_callback = std::move(rhs.m_ssl_context_callback); #endif @@ -120,6 +125,26 @@ class http_listener_config m_timeout = std::move(timeout); } + /// + /// Get the listen backlog + /// + /// The maximum length of the queue of pending connections, or zero for the implementation default. + /// The implementation may not honour this value. + int backlog() const + { + return m_backlog; + } + + /// + /// Set the listen backlog + /// + /// The maximum length of the queue of pending connections, or zero for the implementation default. + /// The implementation may not honour this value. + void set_backlog(int backlog) + { + m_backlog = backlog; + } + #if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) /// /// Get the callback of ssl context @@ -143,6 +168,7 @@ class http_listener_config private: utility::seconds m_timeout; + int m_backlog; #if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO) std::function m_ssl_context_callback; #endif diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 99351c13a0..7fe2a76938 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -122,6 +122,7 @@ namespace class hostport_listener { private: + int m_backlog; std::unique_ptr m_acceptor; std::map m_listeners; pplx::extensibility::reader_writer_lock_t m_listeners_lock; @@ -140,7 +141,8 @@ namespace public: hostport_listener(http_linux_server* server, const std::string& hostport, bool is_https, const http_listener_config& config) - : m_acceptor() + : m_backlog(config.backlog()) + , m_acceptor() , m_listeners() , m_listeners_lock() , m_connections_lock() @@ -482,8 +484,11 @@ void hostport_listener::start() tcp::endpoint endpoint = *resolver.resolve(query); - m_acceptor.reset(new tcp::acceptor(service, endpoint)); - m_acceptor->set_option(tcp::acceptor::reuse_address(true)); + m_acceptor.reset(new tcp::acceptor(service)); + m_acceptor->open(endpoint.protocol()); + m_acceptor->set_option(socket_base::reuse_address(true)); + m_acceptor->bind(endpoint); + m_acceptor->listen(0 != m_backlog ? m_backlog : socket_base::max_connections); auto socket = new ip::tcp::socket(service); m_acceptor->async_accept(*socket, [this, socket](const boost::system::error_code& ec) From 23f1c7c49896b7543af6a12924215a3ca3227ee9 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Tue, 5 Dec 2017 15:41:36 -0800 Subject: [PATCH 176/438] Fix identation (should be spaces) --- Release/include/cpprest/streams.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Release/include/cpprest/streams.h b/Release/include/cpprest/streams.h index 823466aa3b..1aaf95ed9e 100644 --- a/Release/include/cpprest/streams.h +++ b/Release/include/cpprest/streams.h @@ -883,11 +883,11 @@ namespace Concurrency { namespace streams if (ch == concurrency::streams::char_traits::eof()) return pplx::task_from_result(false); if (ch == '\n') { - return buffer.bumpc().then([]( + return buffer.bumpc().then([]( #ifndef _WIN32 // Required by GCC - typename + typename #endif - concurrency::streams::char_traits::int_type) { return false; }); + concurrency::streams::char_traits::int_type) { return false; }); } return pplx::task_from_result(false); }; From 05e474a2d8f041f56691a4e9f7f79bd0f110809c Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Tue, 5 Dec 2017 15:43:17 -0800 Subject: [PATCH 177/438] Typename required by MSVC now too --- Release/include/cpprest/streams.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Release/include/cpprest/streams.h b/Release/include/cpprest/streams.h index 1aaf95ed9e..c928bfd50d 100644 --- a/Release/include/cpprest/streams.h +++ b/Release/include/cpprest/streams.h @@ -884,10 +884,7 @@ namespace Concurrency { namespace streams if (ch == '\n') { return buffer.bumpc().then([]( -#ifndef _WIN32 // Required by GCC - typename -#endif - concurrency::streams::char_traits::int_type) { return false; }); + typename concurrency::streams::char_traits::int_type) { return false; }); } return pplx::task_from_result(false); }; @@ -896,10 +893,7 @@ namespace Concurrency { namespace streams { while ( buffer.in_avail() > 0 ) { -#ifndef _WIN32 // Required by GCC, because concurrency::streams::char_traits is a dependent scope - typename -#endif - concurrency::streams::char_traits::int_type ch; + typename concurrency::streams::char_traits::int_type ch; if (_locals->saw_CR) { From 7946980b9a6aab6962c85cfa9da515d5e0524d5c Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Tue, 5 Dec 2017 16:47:34 -0800 Subject: [PATCH 178/438] Remove :: from ::utility (workaround two-phase msvc bug) --- Release/include/cpprest/http_client.h | 2 +- Release/include/cpprest/http_msg.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Release/include/cpprest/http_client.h b/Release/include/cpprest/http_client.h index 80c48265a1..a936a23ede 100644 --- a/Release/include/cpprest/http_client.h +++ b/Release/include/cpprest/http_client.h @@ -603,7 +603,7 @@ class http_client const method &mtd, const utf16string &path_query_fragment, const utf16string &body_data, - const utf16string &content_type = ::utility::conversions::to_utf16string("text/plain"), + const utf16string &content_type = utility::conversions::to_utf16string("text/plain"), const pplx::cancellation_token &token = pplx::cancellation_token::none()) { http_request msg(mtd); diff --git a/Release/include/cpprest/http_msg.h b/Release/include/cpprest/http_msg.h index 8ca25edc69..083e75713e 100644 --- a/Release/include/cpprest/http_msg.h +++ b/Release/include/cpprest/http_msg.h @@ -568,7 +568,7 @@ class http_response /// /// This will overwrite any previously set body data and "Content-Type" header. /// - void set_body(const utf16string &body_text, utf16string content_type = ::utility::conversions::to_utf16string("text/plain")) + void set_body(const utf16string &body_text, utf16string content_type = utility::conversions::to_utf16string("text/plain")) { if (content_type.find(::utility::conversions::to_utf16string("charset=")) != content_type.npos) { @@ -978,7 +978,7 @@ class http_request /// /// This will overwrite any previously set body data and "Content-Type" header. /// - void set_body(const utf16string &body_text, utf16string content_type = ::utility::conversions::to_utf16string("text/plain")) + void set_body(const utf16string &body_text, utf16string content_type = utility::conversions::to_utf16string("text/plain")) { if(content_type.find(::utility::conversions::to_utf16string("charset=")) != content_type.npos) { @@ -1207,7 +1207,7 @@ class http_request // Callers of this function do NOT need to block waiting for the response to be /// sent to before the body data is destroyed or goes out of scope. /// - pplx::task reply(http::status_code status, const utf16string &body_data, const utf16string &content_type = ::utility::conversions::to_utf16string("text/plain")) const + pplx::task reply(http::status_code status, const utf16string &body_data, const utf16string &content_type = utility::conversions::to_utf16string("text/plain")) const { http_response response(status); response.set_body(body_data, content_type); From 19b67d592bad60a44ed8a20ba7505fb6f468b566 Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Tue, 5 Dec 2017 17:22:44 -0800 Subject: [PATCH 179/438] Fix /Zc:strictStrings issues raised by /permissive- --- Release/src/http/client/x509_cert_utilities.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Release/src/http/client/x509_cert_utilities.cpp b/Release/src/http/client/x509_cert_utilities.cpp index 48c50e07df..1d4e7137e7 100644 --- a/Release/src/http/client/x509_cert_utilities.cpp +++ b/Release/src/http/client/x509_cert_utilities.cpp @@ -431,11 +431,11 @@ bool verify_X509_cert_chain(const std::vector &certChain, const std params.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; LPSTR usages [] = { - szOID_PKIX_KP_SERVER_AUTH, + (LPSTR)szOID_PKIX_KP_SERVER_AUTH, // For older servers and to match IE. - szOID_SERVER_GATED_CRYPTO, - szOID_SGC_NETSCAPE + (LPSTR)szOID_SERVER_GATED_CRYPTO, + (LPSTR)szOID_SGC_NETSCAPE }; params.RequestedUsage.Usage.cUsageIdentifier = std::extent::value; params.RequestedUsage.Usage.rgpszUsageIdentifier = usages; From e56e3d79d8323196292695d728c13216c050c74c Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 5 Dec 2017 18:19:41 -0800 Subject: [PATCH 180/438] Revert regression in c++11 support. Fixes #621. --- Release/include/pplx/pplxtasks.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Release/include/pplx/pplxtasks.h b/Release/include/pplx/pplxtasks.h index 212c6ba4cc..998ecba29d 100644 --- a/Release/include/pplx/pplxtasks.h +++ b/Release/include/pplx/pplxtasks.h @@ -6699,7 +6699,7 @@ auto when_all(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions /// /**/ template -auto operator&&(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs) +auto operator&&(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs) -> decltype(when_all(&_Lhs, &_Lhs)) { task<_ReturnType> _PTasks[2] = {_Lhs, _Rhs}; return when_all(_PTasks, _PTasks+2); @@ -6731,7 +6731,7 @@ auto operator&&(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs) /// /**/ template -auto operator&&(const task> & _Lhs, const task<_ReturnType> & _Rhs) +auto operator&&(const task> & _Lhs, const task<_ReturnType> & _Rhs) -> decltype(details::_WhenAllVectorAndValue(_Lhs, _Rhs, true)) { return details::_WhenAllVectorAndValue(_Lhs, _Rhs, true); } @@ -6762,7 +6762,7 @@ auto operator&&(const task> & _Lhs, const task<_ReturnT /// /**/ template -auto operator&&(const task<_ReturnType> & _Lhs, const task> & _Rhs) +auto operator&&(const task<_ReturnType> & _Lhs, const task> & _Rhs) -> decltype(details::_WhenAllVectorAndValue(_Rhs, _Lhs, false)) { return details::_WhenAllVectorAndValue(_Rhs, _Lhs, false); } @@ -6793,7 +6793,7 @@ auto operator&&(const task<_ReturnType> & _Lhs, const task /**/ template -auto operator&&(const task> & _Lhs, const task> & _Rhs) +auto operator&&(const task> & _Lhs, const task> & _Rhs) -> decltype(when_all(&_Lhs, &_Lhs)) { task> _PTasks[2] = {_Lhs, _Rhs}; return when_all(_PTasks, _PTasks+2); @@ -7084,7 +7084,7 @@ auto when_any(_Iterator _Begin, _Iterator _End, cancellation_token _Cancellation /// /**/ template -auto operator||(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs) +task<_ReturnType> operator||(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs) { auto _PParam = new details::_RunAnyParam>(); @@ -7145,7 +7145,7 @@ auto operator||(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs) /// /**/ template -auto operator||(const task> & _Lhs, const task<_ReturnType> & _Rhs) +task> operator||(const task> & _Lhs, const task<_ReturnType> & _Rhs) { auto _PParam = new details::_RunAnyParam, details::_CancellationTokenState *>>(); @@ -7219,7 +7219,7 @@ auto operator||(const task> & _Lhs, const task<_ReturnT /// /**/ template -auto operator||(const task<_ReturnType> & _Lhs, const task> & _Rhs) +auto operator||(const task<_ReturnType> & _Lhs, const task> & _Rhs) -> decltype(_Rhs || _Lhs) { return _Rhs || _Lhs; } From 242da36338b73198e892a439550d41db4233990f Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 5 Dec 2017 18:20:08 -0800 Subject: [PATCH 181/438] Remove excessive specialization of type_parser to improve compiler throughput. --- Release/include/cpprest/streams.h | 51 +++---------------------------- 1 file changed, 4 insertions(+), 47 deletions(-) diff --git a/Release/include/cpprest/streams.h b/Release/include/cpprest/streams.h index c928bfd50d..7e240c0c94 100644 --- a/Release/include/cpprest/streams.h +++ b/Release/include/cpprest/streams.h @@ -1711,55 +1711,11 @@ class type_parser : public _type_parser_base }; #ifdef _WIN32 -template<> -class type_parser> : public _type_parser_base +template +class type_parser>> : public _type_parser_base { public: - static pplx::task parse(streams::streambuf buffer) - { - return _parse_input,std::basic_string>(buffer, _accept_char, _extract_result); - } - -private: - static bool _accept_char(const std::shared_ptr> &state, int_type ch) - { - if ( ch == concurrency::streams::char_traits::eof() || isspace(ch)) return false; - state->push_back(char(ch)); - return true; - } - static pplx::task> _extract_result(std::shared_ptr> state) - { - return pplx::task_from_result(utility::conversions::utf8_to_utf16(*state)); - } -}; - -template<> -class type_parser> : public _type_parser_base -{ -public: - static pplx::task parse(streams::streambuf buffer) - { - return _parse_input,std::basic_string>(buffer, _accept_char, _extract_result); - } - -private: - static bool _accept_char(const std::shared_ptr> &state, int_type ch) - { - if ( ch == concurrency::streams::char_traits::eof() || isspace(ch)) return false; - state->push_back(char(ch)); - return true; - } - static pplx::task> _extract_result(std::shared_ptr> state) - { - return pplx::task_from_result(utility::conversions::utf8_to_utf16(*state)); - } -}; - -template<> -class type_parser> : public _type_parser_base -{ -public: - static pplx::task parse(streams::streambuf buffer) + static pplx::task parse(streams::streambuf buffer) { return _parse_input,std::basic_string>(buffer, _accept_char, _extract_result); } @@ -1781,3 +1737,4 @@ class type_parser> : public _type_parse }} #endif + From c258a4ac4d62f7550f51800588ca89699e9ffc84 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 14 Dec 2017 18:38:39 -0800 Subject: [PATCH 182/438] Remove NOMINMAX definition to better catch Windows.h issues in the future. --- Release/include/pplx/pplxtasks.h | 1 + .../src/http/client/http_client_winhttp.cpp | 4 ++++ Release/src/http/common/http_msg.cpp | 4 ++++ .../src/http/listener/http_server_httpsys.cpp | 5 ++++- Release/src/json/json.cpp | 4 ++++ Release/src/pch/stdafx.h | 20 ++++--------------- .../src/websockets/client/ws_client_wspp.cpp | 5 +++++ .../tests/common/utilities/os_utilities.cpp | 2 +- 8 files changed, 27 insertions(+), 18 deletions(-) diff --git a/Release/include/pplx/pplxtasks.h b/Release/include/pplx/pplxtasks.h index 998ecba29d..e784306d40 100644 --- a/Release/include/pplx/pplxtasks.h +++ b/Release/include/pplx/pplxtasks.h @@ -7332,4 +7332,5 @@ namespace concurrency = Concurrency; #endif #endif // _PPLXTASKS_H + diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 60a4d060d5..07f5fdb3b9 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -21,6 +21,9 @@ #include #endif +#undef min +#undef max + namespace web { namespace http @@ -1527,3 +1530,4 @@ std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage( } }}}} + diff --git a/Release/src/http/common/http_msg.cpp b/Release/src/http/common/http_msg.cpp index 6a857d7531..363d49c158 100644 --- a/Release/src/http/common/http_msg.cpp +++ b/Release/src/http/common/http_msg.cpp @@ -13,6 +13,9 @@ #include "stdafx.h" #include "../common/internal_http_helpers.h" +#undef min +#undef max + using namespace web; using namespace utility; using namespace concurrency; @@ -1043,3 +1046,4 @@ details::_http_request::_http_request(std::unique_ptr make_http_httpsys_server() }}}} -#endif \ No newline at end of file +#endif diff --git a/Release/src/json/json.cpp b/Release/src/json/json.cpp index e5a6089aea..04ddbe0fe4 100644 --- a/Release/src/json/json.cpp +++ b/Release/src/json/json.cpp @@ -13,6 +13,9 @@ #include "stdafx.h" +#undef min +#undef max + using namespace web; bool json::details::g_keep_json_object_unsorted = false; @@ -516,3 +519,4 @@ const web::json::details::json_error_category_impl& web::json::details::json_err #endif return instance; } + diff --git a/Release/src/pch/stdafx.h b/Release/src/pch/stdafx.h index 6f61163dfe..1532db2f54 100644 --- a/Release/src/pch/stdafx.h +++ b/Release/src/pch/stdafx.h @@ -19,9 +19,6 @@ #pragma clang diagnostic ignored "-Winfinite-recursion" #endif -#include "cpprest/details/cpprest_compat.h" -#include "cpprest/details/basic_types.h" - #ifdef _WIN32 #ifdef CPPREST_TARGET_XP #include @@ -37,12 +34,7 @@ #include #endif -#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -// Windows Header Files: -#define NOMINMAX -#endif - #include #include @@ -96,6 +88,9 @@ #include #include +#include "cpprest/details/cpprest_compat.h" +#include "cpprest/details/basic_types.h" + #include "pplx/pplxtasks.h" #include "cpprest/version.h" @@ -140,13 +135,6 @@ #endif // _WIN32_WINNT >= _WIN32_WINNT_VISTA #endif -#if defined(max) -#error: max macro defined -- make sure to #define NOMINMAX before including windows.h -#endif -#if defined(min) -#error: min macro defined -- make sure to #define NOMINMAX before including windows.h -#endif - #if defined(__clang__) #pragma clang diagnostic pop -#endif +#endif diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index e9e7658b18..78c443a27a 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -20,6 +20,10 @@ #include "ws_client_impl.h" +// These must be undef'ed before including websocketpp because it is not Windows.h safe. +#undef min +#undef max + // Force websocketpp to use C++ std::error_code instead of Boost. #define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_ #if defined(_MSC_VER) @@ -792,3 +796,4 @@ websocket_callback_client::websocket_callback_client(websocket_client_config con }}} #endif + diff --git a/Release/tests/common/utilities/os_utilities.cpp b/Release/tests/common/utilities/os_utilities.cpp index 1172b732bb..639460078e 100644 --- a/Release/tests/common/utilities/os_utilities.cpp +++ b/Release/tests/common/utilities/os_utilities.cpp @@ -15,7 +15,6 @@ #ifdef WIN32 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define NOMINMAX #include #else #include @@ -55,3 +54,4 @@ long os_utilities::interlocked_exchange(volatile long *target, long value) } }}} + From bd4afa3b18bf5fddbe9fe2b88b527137655f6cfc Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 14 Dec 2017 18:48:07 -0800 Subject: [PATCH 183/438] Fix warnings on GCC7. --- Release/samples/Oauth1Client/Oauth1Client.cpp | 5 +++-- Release/samples/Oauth2Client/Oauth2Client.cpp | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Release/samples/Oauth1Client/Oauth1Client.cpp b/Release/samples/Oauth1Client/Oauth1Client.cpp index 065f0a1516..d360d37d54 100644 --- a/Release/samples/Oauth1Client/Oauth1Client.cpp +++ b/Release/samples/Oauth1Client/Oauth1Client.cpp @@ -64,11 +64,11 @@ static void open_browser(utility::string_t auth_uri) #elif defined(__APPLE__) // NOTE: OS X only. string_t browser_cmd(U("open \"") + auth_uri + U("\"")); - system(browser_cmd.c_str()); + (void)system(browser_cmd.c_str()); #else // NOTE: Linux/X11 only. string_t browser_cmd(U("xdg-open \"") + auth_uri + U("\"")); - system(browser_cmd.c_str()); + (void)system(browser_cmd.c_str()); #endif } @@ -301,3 +301,4 @@ int main(int argc, char *argv[]) ucout << "Done." << std::endl; return 0; } + diff --git a/Release/samples/Oauth2Client/Oauth2Client.cpp b/Release/samples/Oauth2Client/Oauth2Client.cpp index 3b988f00b3..59a963eaff 100644 --- a/Release/samples/Oauth2Client/Oauth2Client.cpp +++ b/Release/samples/Oauth2Client/Oauth2Client.cpp @@ -67,11 +67,11 @@ static void open_browser(utility::string_t auth_uri) #elif defined(__APPLE__) // NOTE: OS X only. string_t browser_cmd(U("open \"") + auth_uri + U("\"")); - system(browser_cmd.c_str()); + (void)system(browser_cmd.c_str()); #else // NOTE: Linux/X11 only. string_t browser_cmd(U("xdg-open \"") + auth_uri + U("\"")); - system(browser_cmd.c_str()); + (void)system(browser_cmd.c_str()); #endif } @@ -321,3 +321,4 @@ int main(int argc, char *argv[]) ucout << "Done." << std::endl; return 0; } + From e8dda215426172cd348e4d6d455141f40768bf47 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 14 Dec 2017 18:57:43 -0800 Subject: [PATCH 184/438] Push version number to 2.10.1 --- Build/version.props | 2 +- Release/include/cpprest/version.h | 3 ++- Release/src/CMakeLists.txt | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Build/version.props b/Build/version.props index 13b7b76e69..cbf33ac51b 100644 --- a/Build/version.props +++ b/Build/version.props @@ -4,7 +4,7 @@ cpprest 2 10 - 0 + 1 $(CppRestSDKVersionMajor)_$(CppRestSDKVersionMinor) $(CppRestSDKVersionMajor).$(CppRestSDKVersionMinor) diff --git a/Release/include/cpprest/version.h b/Release/include/cpprest/version.h index c91a3db40a..2324dddddb 100644 --- a/Release/include/cpprest/version.h +++ b/Release/include/cpprest/version.h @@ -3,8 +3,9 @@ * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. * */ -#define CPPREST_VERSION_REVISION 0 +#define CPPREST_VERSION_REVISION 1 #define CPPREST_VERSION_MINOR 10 #define CPPREST_VERSION_MAJOR 2 #define CPPREST_VERSION (CPPREST_VERSION_MAJOR*100000+CPPREST_VERSION_MINOR*100+CPPREST_VERSION_REVISION) + diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index b862e44117..3f8a0f8d88 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_policy(SET CMP0022 NEW) set(CPPREST_VERSION_MAJOR 2) set(CPPREST_VERSION_MINOR 10) -set(CPPREST_VERSION_REVISION 0) +set(CPPREST_VERSION_REVISION 1) file(GLOB HEADERS_CPPREST "../include/cpprest/*.h" "../include/cpprest/*.hpp" "../include/cpprest/*.dat") file(GLOB HEADERS_PPLX "../include/pplx/*.h" "../include/pplx/*.hpp") From c7444407f66c47739af107bba63aafe133d1e945 Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Fri, 15 Dec 2017 11:14:35 +0000 Subject: [PATCH 185/438] Default the debug postfix for library filenames to "d" on Windows (it may still be overridden to the empty string) --- Release/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 218adcbb34..2b0e8d5f7b 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -32,6 +32,10 @@ else() set(BUILD_SAMPLES ON CACHE BOOL "Build sample applications.") endif() +if(WIN32) + set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Default filename postfix for libraries under configuration DEBUG") +endif() + if(ANDROID) set(Boost_USE_STATIC_LIBS ON CACHE BOOL "Link against boost statically.") else() From 3e8dcf5b574fa7f23920de3166e03fee5bf5aae1 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 19 Dec 2017 04:14:17 -0800 Subject: [PATCH 186/438] Fix UWP issues with min/max macros. --- Release/include/cpprest/streams.h | 1 + Release/src/http/client/http_client_winrt.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/Release/include/cpprest/streams.h b/Release/include/cpprest/streams.h index 7e240c0c94..60d5504e78 100644 --- a/Release/include/cpprest/streams.h +++ b/Release/include/cpprest/streams.h @@ -1714,6 +1714,7 @@ class type_parser : public _type_parser_base template class type_parser>> : public _type_parser_base { + typedef typename concurrency::streams::streambuf::int_type int_type; public: static pplx::task parse(streams::streambuf buffer) { diff --git a/Release/src/http/client/http_client_winrt.cpp b/Release/src/http/client/http_client_winrt.cpp index 697f48a337..4ada65a75b 100644 --- a/Release/src/http/client/http_client_winrt.cpp +++ b/Release/src/http/client/http_client_winrt.cpp @@ -28,6 +28,9 @@ using namespace std; using namespace Platform; using namespace Microsoft::WRL; +#undef min +#undef max + namespace web { namespace http From 81d67e44e36f3e8aa05a19db3c0847c97d945836 Mon Sep 17 00:00:00 2001 From: garethsb-sony Date: Wed, 20 Dec 2017 10:24:55 +0000 Subject: [PATCH 187/438] Handle std::range_error (from count_utf16_to_utf8) like web::uri_exception --- Release/src/http/listener/http_server_asio.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 99351c13a0..fcc531ecfe 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -637,7 +637,7 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys { m_request.set_request_uri(utility::conversions::to_string_t(http_path_and_version.substr(1, http_path_and_version.size() - VersionPortionSize - 1))); } - catch(const web::uri_exception &e) + catch (const std::exception& e) // may be std::range_error indicating invalid Unicode, or web::uri_exception { m_request.reply(status_codes::BadRequest, e.what()); m_close = true; @@ -913,7 +913,7 @@ will_deref_and_erase_t asio_server_connection::dispatch_request_to_listener() { pListener = m_p_parent->find_listener(m_request.relative_uri()); } - catch (const web::uri_exception&) + catch (const std::exception&) // may be web::uri_exception, or std::range_error indicating invalid Unicode { m_request.reply(status_codes::BadRequest); (will_erase_from_parent_t)do_response(); From 7105325b30aa8405ab6ee061e8677fde79aa9435 Mon Sep 17 00:00:00 2001 From: Jonathan Gawrych Date: Thu, 21 Dec 2017 18:49:25 -0800 Subject: [PATCH 188/438] Fix string use after destruct introduced in merge commit b7fa0b1 --- Release/src/http/client/http_client_winhttp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 07f5fdb3b9..66ca12ddd1 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -412,6 +412,7 @@ class winhttp_client : public _http_client_communicator DWORD access_type; LPCWSTR proxy_name; LPCWSTR proxy_bypass = WINHTTP_NO_PROXY_BYPASS; + utility::string_t proxy_str; http::uri uri; const auto& config = client_config(); @@ -485,7 +486,6 @@ class winhttp_client : public _http_client_communicator } else { - utility::string_t proxy_str; if (uri.port() > 0) { utility::ostringstream_t ss; From 6b2e0480018530b616f61d5cdc786c92ba148bb7 Mon Sep 17 00:00:00 2001 From: John Hruby Date: Tue, 26 Dec 2017 16:52:13 +0100 Subject: [PATCH 189/438] fixed strand --- .../libs/websocketpp/websocketpp/transport/asio/connection.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/libs/websocketpp/websocketpp/transport/asio/connection.hpp b/Release/libs/websocketpp/websocketpp/transport/asio/connection.hpp index 0be40f6b45..395632c3f3 100644 --- a/Release/libs/websocketpp/websocketpp/transport/asio/connection.hpp +++ b/Release/libs/websocketpp/websocketpp/transport/asio/connection.hpp @@ -422,7 +422,7 @@ class connection : public config::socket_type::socket_con_type { m_io_service = io_service; if (config::enable_multithreading) { - m_strand = lib::make_shared( + m_strand = lib::make_shared( lib::ref(*io_service)); m_async_read_handler = m_strand->wrap(lib::bind( From 31ec7923b1eaf06567cea3bb7760f78ce44c447e Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 3 Jan 2018 14:09:21 -0800 Subject: [PATCH 190/438] Extract the abi tag to make it more platform independent. --- Release/CMakeLists.txt | 20 ++++++++++++++++++-- Release/src/CMakeLists.txt | 17 +---------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 2b0e8d5f7b..416d5c1496 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -4,11 +4,15 @@ if(POLICY CMP0042) cmake_policy(SET CMP0042 NEW) # use MACOSX_RPATH endif() if(UNIX) - project(cpprest C CXX) + project(cpprestsdk C CXX) else() - project(cpprest CXX) + project(cpprestsdk CXX) endif() +set(CPPREST_VERSION_MAJOR 2) +set(CPPREST_VERSION_MINOR 10) +set(CPPREST_VERSION_REVISION 1) + enable_testing() set(WERROR ON CACHE BOOL "Treat Warnings as Errors.") @@ -34,6 +38,18 @@ endif() if(WIN32) set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Default filename postfix for libraries under configuration DEBUG") +else() + set(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Default filename postfix for libraries under configuration DEBUG") +endif() + +if(WIN32) + set(TOOLSET) + if(CMAKE_VS_PLATFORM_TOOLSET) + string(REGEX REPLACE "^v" "" TOOLSET "${CMAKE_VS_PLATFORM_TOOLSET}") + endif() + set(CPPREST_ABI_TAG "${TOOLSET}_${CPPREST_VERSION_MAJOR}_${CPPREST_VERSION_MINOR}" CACHE STRING "Postfix tag for the cpprest abi") +else() + set(CPPREST_ABI_TAG "" CACHE STRING "Postfix tag for the cpprest abi") endif() if(ANDROID) diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 26dcc32ba3..a37a8cff9d 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -1,9 +1,5 @@ cmake_policy(SET CMP0022 NEW) -set(CPPREST_VERSION_MAJOR 2) -set(CPPREST_VERSION_MINOR 10) -set(CPPREST_VERSION_REVISION 1) - file(GLOB HEADERS_CPPREST "../include/cpprest/*.h" "../include/cpprest/*.hpp" "../include/cpprest/*.dat") file(GLOB HEADERS_PPLX "../include/pplx/*.h" "../include/pplx/*.hpp") file(GLOB HEADERS_DETAILS "../include/cpprest/details/*.h" "../include/cpprest/details/*.hpp" "../include/cpprest/details/*.dat" "../include/pplx/*.hpp" "../include/pplx/*.dat") @@ -214,19 +210,8 @@ elseif(WINDOWS_STORE) endif() endif() +set_target_properties(cpprest PROPERTIES OUTPUT_NAME "cpprest${CPPREST_ABI_TAG}") if(WIN32) - string(SUBSTRING ${CMAKE_VS_PLATFORM_TOOLSET} 1 -1 TOOLSET) - set(CPPREST_VERSION_POSTFIX "_${CPPREST_VERSION_MAJOR}_${CPPREST_VERSION_MINOR}") - foreach(CFG ${CMAKE_CONFIGURATION_TYPES}) - string(TOUPPER ${CFG} CFG) - get_target_property(CFG_POSTFIX cpprest ${CFG}_POSTFIX) - if (NOT CFG_POSTFIX) - # forget "NOTFOUND" - set(CFG_POSTFIX) - endif() - set_target_properties(cpprest PROPERTIES - ${CFG}_POSTFIX "${TOOLSET}${CFG_POSTFIX}${CPPREST_VERSION_POSTFIX}") - endforeach() elseif(ANDROID) # Do not use SOVERSION on android. It is completely unsupported (and causes problems). # Perhaps revisit in the future? (NDK r9d, 8/7/14) From 17a198081379384ed9373828f905592ce9c4bdf3 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 3 Jan 2018 14:09:36 -0800 Subject: [PATCH 191/438] Fix warning due to boost 1.66 --- Release/include/pplx/threadpool.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Release/include/pplx/threadpool.h b/Release/include/pplx/threadpool.h index c67db358a0..db1e97c870 100644 --- a/Release/include/pplx/threadpool.h +++ b/Release/include/pplx/threadpool.h @@ -67,9 +67,10 @@ class threadpool boost::asio::io_service& service() { return m_service; } protected: - threadpool(size_t num_threads) : m_service(num_threads) {} + threadpool(size_t num_threads) : m_service(static_cast(num_threads)) {} boost::asio::io_service m_service; }; } + From 3f04578f98d1356dc6898a2d55fa8bed3d485a48 Mon Sep 17 00:00:00 2001 From: dimarusyy Date: Thu, 4 Jan 2018 11:18:16 +0200 Subject: [PATCH 192/438] #643 : ssl proxy port is hard coded to 443 - use base URI port in "CONNECT" request to proxy server --- Release/src/http/client/http_client_asio.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 19e09b2427..e726760f2d 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -450,12 +450,13 @@ class asio_context : public request_context, public std::enable_shared_from_this const auto &base_uri = m_context->m_http_client->base_uri(); const auto &host = utility::conversions::to_utf8string(base_uri.host()); + const auto &port = base_uri.port(); std::ostream request_stream(&m_request); request_stream.imbue(std::locale::classic()); - request_stream << "CONNECT " << host << ":" << 443 << " HTTP/1.1" << CRLF; - request_stream << "Host: " << host << ":" << 443 << CRLF; + request_stream << "CONNECT " << host << ":" << ((port != 0) ? port : 443) << " HTTP/1.1" << CRLF; + request_stream << "Host: " << host << ":" << ((port != 0) ? port : 443) << CRLF; request_stream << "Proxy-Connection: Keep-Alive" << CRLF; if(m_context->m_http_client->client_config().proxy().credentials().is_set()) From 88fa4d27ec3fb1239a85114e8254ce3664b45fc8 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 9 Jan 2018 02:39:06 -0800 Subject: [PATCH 193/438] Fix Windows build regression (do not include sys/time.h) --- Release/include/cpprest/asyncrt_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index 064d00f9c2..ad49baa5c3 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -23,11 +23,11 @@ #include "cpprest/details/basic_types.h" #if !defined(_WIN32) || (_MSC_VER >= 1700) -#include #include #endif #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 From b8d1c063ae4f366a3725d20e97ff1d6f2e488467 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 9 Jan 2018 02:52:18 -0800 Subject: [PATCH 194/438] Fix build regression on Windows (CHECK_INCLUDE_FILES requires C language support) --- Release/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 6d18afae1b..9b90129eaf 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -77,7 +77,10 @@ if(CPPREST_EXCLUDE_WEBSOCKETS) set(CPPREST_WEBSOCKETS_IMPL none CACHE STRING "Internal use.") endif() -CHECK_INCLUDE_FILES(xlocale.h HAVE_XLOCALE_H) +if(NOT WIN32) + CHECK_INCLUDE_FILES(xlocale.h HAVE_XLOCALE_H) +endif() + if(APPLE) # Note: also iOS set(CPPREST_PPLX_IMPL apple CACHE STRING "Internal use.") set(CPPREST_WEBSOCKETS_IMPL wspp CACHE STRING "Internal use.") From 391540826cf4e81c0138d58af102f8dc1e1f2dcf Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 24 Jan 2018 08:29:09 -0800 Subject: [PATCH 195/438] Disable "disable_sni" test due to lack of robust test servers. The current test can be run and does pass, but relies on a timeout. --- .../functional/websockets/client/authentication_tests.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Release/tests/functional/websockets/client/authentication_tests.cpp b/Release/tests/functional/websockets/client/authentication_tests.cpp index 5db5207697..00a498cb67 100644 --- a/Release/tests/functional/websockets/client/authentication_tests.cpp +++ b/Release/tests/functional/websockets/client/authentication_tests.cpp @@ -162,15 +162,18 @@ TEST(sni_with_older_server_test) } // WinRT doesn't expose option for disabling. -TEST(disable_sni) +// No stable server is available to reliably test this. +// The configuration below relies on a timeout in the success case. +TEST(disable_sni, "Ignore", "Manual") { websocket_client_config config; + config.set_server_name("expired.badssl.com"); config.disable_sni(); websocket_client client(config); try { - client.connect(U("wss://swordsoftruth.com")).wait(); + client.connect(U("wss://badssl.com")).wait(); // Should never be reached. VERIFY_IS_TRUE(false); @@ -239,3 +242,4 @@ TEST(cert_expired) }}}} #endif + From eba38b867dcf6749d9612f21c6b7cf1ef9d1625f Mon Sep 17 00:00:00 2001 From: Gareth Sylvester-Bradley <31761158+garethsb-sony@users.noreply.github.com> Date: Wed, 24 Jan 2018 16:31:59 +0000 Subject: [PATCH 196/438] Making crossplat::threadpool::shared_instance() safe to use in cpprest DLL (#611) * When the C++ REST SDK is built as a DLL on Windows, and unloaded before the process exits, the crossplat::threadpool::shared_instance() is destroyed at DLL_PROCESS_DETACH, at which stage joining threads causes deadlock. Use the workaround provided by asio to terminate the threads in this case. * Take 2. We can't just use TerminateThread indiscriminately because the thread may be holding e.g. the heap lock, so we need to ensure the thread is in a known state. Rather than reinvent the wheel, use asio's own thread class which already provides the necessary mechanism. * Export the shared instance to allow cross-platform implementation of functionality (e.g. complete_after) that needs access to the io_service when using the asio-based default scheduler * Use improved shutdown logic even when building as static lib, because users could include it in a DLL. --- Release/include/pplx/threadpool.h | 2 +- Release/src/pplx/threadpool.cpp | 65 ++++++++++++++++--------------- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/Release/include/pplx/threadpool.h b/Release/include/pplx/threadpool.h index db1e97c870..919eb75552 100644 --- a/Release/include/pplx/threadpool.h +++ b/Release/include/pplx/threadpool.h @@ -52,7 +52,7 @@ using java_local_ref = std::unique_ptr::type, ja class threadpool { public: - static threadpool& shared_instance(); + _ASYNCRTIMP static threadpool& shared_instance(); _ASYNCRTIMP static std::unique_ptr __cdecl construct(size_t num_threads); virtual ~threadpool() = default; diff --git a/Release/src/pplx/threadpool.cpp b/Release/src/pplx/threadpool.cpp index 8d3eadadc6..d2dc6161a2 100644 --- a/Release/src/pplx/threadpool.cpp +++ b/Release/src/pplx/threadpool.cpp @@ -9,16 +9,7 @@ #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) || !defined(_WIN32) #include "pplx/threadpool.h" -#if !defined(_WIN32) -#define CPPREST_PTHREADS -#endif - -#if defined(CPPREST_PTHREADS) -#include -#else -#include -#endif - +#include #include #if defined(__ANDROID__) @@ -44,27 +35,14 @@ struct threadpool_impl final : crossplat::threadpool m_service.stop(); for (auto iter = m_threads.begin(); iter != m_threads.end(); ++iter) { -#if defined(CPPREST_PTHREADS) - pthread_t t = *iter; - void* res; - pthread_join(t, &res); -#else - iter->join(); -#endif + (*iter)->join(); } } private: void add_thread() { -#ifdef CPPREST_PTHREADS - pthread_t t; - auto result = pthread_create(&t, nullptr, &thread_start, this); - if (result == 0) - m_threads.push_back(t); -#else - m_threads.push_back(std::thread(&thread_start, this)); -#endif + m_threads.push_back(std::unique_ptr(new boost::asio::detail::thread([&]{ thread_start(this); }))); } #if defined(__ANDROID__) @@ -89,11 +67,7 @@ struct threadpool_impl final : crossplat::threadpool return arg; } -#if defined(CPPREST_PTHREADS) - std::vector m_threads; -#else - std::vector m_threads; -#endif + std::vector> m_threads; boost::asio::io_service::work m_work; }; } @@ -133,6 +107,35 @@ threadpool& threadpool::shared_instance() return s_shared; } +#elif defined(_WIN32) + +// if linked into a DLL, the threadpool shared instance will be destroyed at DLL_PROCESS_DETACH, +// at which stage joining threads causes deadlock, hence this dance +threadpool& threadpool::shared_instance() +{ + static bool terminate_threads = false; + static struct restore_terminate_threads + { + ~restore_terminate_threads() + { + boost::asio::detail::thread::set_terminate_threads(terminate_threads); + } + } destroyed_after; + + static threadpool_impl s_shared(40); + + static struct enforce_terminate_threads + { + ~enforce_terminate_threads() + { + terminate_threads = boost::asio::detail::thread::terminate_threads(); + boost::asio::detail::thread::set_terminate_threads(true); + } + } destroyed_before; + + return s_shared; +} + #else // initialize the static shared threadpool @@ -156,4 +159,4 @@ std::unique_ptr crossplat::threadpool::construct(size_t n { return std::unique_ptr(new threadpool_impl(num_threads)); } -#endif \ No newline at end of file +#endif From 859292a8f70c2e4ae91c585a3d448ab345b0f989 Mon Sep 17 00:00:00 2001 From: Mathy Vanvoorden Date: Wed, 24 Jan 2018 20:15:38 +0100 Subject: [PATCH 197/438] Make it possible to set the user agent for websockets (#606) * Make it possible to set the user agent for websockets * Use headers() to communicate the user agent for websockets. * Fix set_user_agent on Linux; use to_string_t. --- Release/include/cpprest/ws_client.h | 6 ++++++ Release/src/websockets/client/ws_client_wspp.cpp | 10 +++++++++- Release/src/websockets/client/ws_msg.cpp | 6 ++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Release/include/cpprest/ws_client.h b/Release/include/cpprest/ws_client.h index 9c9e5d818d..9a324cde51 100644 --- a/Release/include/cpprest/ws_client.h +++ b/Release/include/cpprest/ws_client.h @@ -150,6 +150,12 @@ class websocket_client_config return m_sni_hostname; } + /// + /// Sets the User Agent to be used for the connection + /// + /// The User Agent to use, as a string. + _ASYNCRTIMP void set_user_agent(const utf8string &user_agent); + /// /// Gets the headers of the HTTP request message used in the WebSocket protocol handshake. /// diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index 5074ebb062..8f2658a8f5 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -316,6 +316,15 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: shutdown_wspp_impl(con_hdl, false); }); + // Set User Agent specified by the user. This needs to happen before any connection is created + const auto& headers = m_config.headers(); + + auto user_agent_it = headers.find(web::http::header_names::user_agent); + if (user_agent_it != headers.end()) + { + client.set_user_agent(utility::conversions::to_utf8string(user_agent_it->second)); + } + // Get the connection handle to save for later, have to create temporary // because type erasure occurs with connection_hdl. websocketpp::lib::error_code ec; @@ -327,7 +336,6 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: } // Add any request headers specified by the user. - const auto & headers = m_config.headers(); for (const auto & header : headers) { if (!utility::details::str_icmp(header.first, g_subProtocolHeader)) diff --git a/Release/src/websockets/client/ws_msg.cpp b/Release/src/websockets/client/ws_msg.cpp index 10bce338e6..1d24409c67 100644 --- a/Release/src/websockets/client/ws_msg.cpp +++ b/Release/src/websockets/client/ws_msg.cpp @@ -28,6 +28,12 @@ namespace client { static ::utility::string_t g_subProtocolHeader = _XPLATSTR("Sec-WebSocket-Protocol"); + +void websocket_client_config::set_user_agent(const utf8string &user_agent) +{ + headers().add(web::http::header_names::user_agent, utility::conversions::to_string_t(user_agent)); +} + void websocket_client_config::add_subprotocol(const ::utility::string_t &name) { m_headers.add(g_subProtocolHeader, name); From fec80b0fdc59226cbb00dedffbb54b624bab3383 Mon Sep 17 00:00:00 2001 From: juntek Date: Wed, 24 Jan 2018 20:30:21 +0100 Subject: [PATCH 198/438] fixes #628 (#629) From 7db35851c16ecbe79a42f4ea4647cef647b7bf2c Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 24 Jan 2018 11:35:53 -0800 Subject: [PATCH 199/438] Fix min/max issues on Windows. --- Release/src/http/client/http_client_asio.cpp | 3 +++ Release/src/http/listener/http_server_asio.cpp | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 1e41ebe8f0..4ba3e0851b 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -15,6 +15,9 @@ #include "stdafx.h" +#undef min +#undef max + #include "cpprest/asyncrt_utils.h" #include "../common/internal_http_helpers.h" diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index c1d9791726..3fadebb03b 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -13,6 +13,10 @@ * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ #include "stdafx.h" + +#undef min +#undef max + #include #include #include From 639726178046803d7193785b2eb2e75137df40f3 Mon Sep 17 00:00:00 2001 From: Gareth Sylvester-Bradley <31761158+garethsb-sony@users.noreply.github.com> Date: Wed, 24 Jan 2018 22:53:59 +0000 Subject: [PATCH 200/438] Add support for retrieving HTTP version of a request in HTTP listener (#565) * Grab HTTP protocol version from the underlying request message and expose in http_request * Use error_code overload to resolve https://github.com/Microsoft/cpprestsdk/issues/545 * Rename get_http_version and get_remote_address without 'get_' prefix for consistency with rest of class public interface * Add test case for http_version * Fix GCC "error: changes meaning of 'http_version'..." that should have been in commit:1ba5ebfd * Use struct for http_version instead of pair. * Restore get_remote_address to avoid breaking source compat --- Release/include/cpprest/http_msg.h | 43 +++++++++++++++++++ Release/src/http/common/http_msg.cpp | 10 ++++- .../src/http/listener/http_server_asio.cpp | 22 +++++++++- .../src/http/listener/http_server_httpsys.cpp | 2 + .../http/listener/request_handler_tests.cpp | 35 ++++++++++++++- 5 files changed, 107 insertions(+), 5 deletions(-) diff --git a/Release/include/cpprest/http_msg.h b/Release/include/cpprest/http_msg.h index 083e75713e..6b49bc4960 100644 --- a/Release/include/cpprest/http_msg.h +++ b/Release/include/cpprest/http_msg.h @@ -43,6 +43,34 @@ namespace client class http_client; } +/// +/// Represents the HTTP protocol version of a message, as {major, minor}. +/// +struct http_version +{ + uint8_t major; + uint8_t minor; + + inline bool operator==(const http_version& other) const { return major == other.major && minor == other.minor; } + inline bool operator<(const http_version& other) const { return major < other.major || (major == other.major && minor < other.minor); } + + inline bool operator!=(const http_version& other) const { return !(*this == other); } + inline bool operator>=(const http_version& other) const { return !(*this < other); } + inline bool operator>(const http_version& other) const { return !(*this < other || *this == other); } + inline bool operator<=(const http_version& other) const { return *this < other || *this == other; } +}; + +/// +/// Predefined HTTP protocol versions. +/// +class http_versions +{ +public: + _ASYNCRTIMP static const http_version HTTP_0_9; + _ASYNCRTIMP static const http_version HTTP_1_0; + _ASYNCRTIMP static const http_version HTTP_1_1; +}; + /// /// Predefined method strings for the standard HTTP methods mentioned in the /// HTTP 1.1 specification. @@ -715,6 +743,8 @@ class _http_request final : public http::details::http_msg_base, public std::ena _ASYNCRTIMP void set_request_uri(const uri&); + http::http_version http_version() const { return m_http_version; } + const utility::string_t& remote_address() const { return m_remote_address; } const pplx::cancellation_token &cancellation_token() const { return m_cancellationToken; } @@ -757,6 +787,8 @@ class _http_request final : public http::details::http_msg_base, public std::ena void _set_base_uri(const http::uri &base_uri) { m_base_uri = base_uri; } + void _set_http_version(const http::http_version &http_version) { m_http_version = http_version; } + void _set_remote_address(const utility::string_t &remote_address) { m_remote_address = remote_address; } private: @@ -783,6 +815,8 @@ class _http_request final : public http::details::http_msg_base, public std::ena pplx::task_completion_event m_response; + http::http_version m_http_version; + utility::string_t m_remote_address; }; @@ -875,10 +909,19 @@ class http_request /// const http_headers &headers() const { return _m_impl->headers(); } + /// + /// Returns the HTTP protocol version of this request message. + /// + /// The HTTP protocol version. + http::http_version http_version() const { return _m_impl->http_version(); } + /// /// Returns a string representation of the remote IP address. /// /// The remote IP address. + const utility::string_t& remote_address() const { return _m_impl->remote_address(); } + + CASABLANCA_DEPRECATED("Use `remote_address()` instead.") const utility::string_t& get_remote_address() const { return _m_impl->remote_address(); } /// diff --git a/Release/src/http/common/http_msg.cpp b/Release/src/http/common/http_msg.cpp index 363d49c158..5e6eb73386 100644 --- a/Release/src/http/common/http_msg.cpp +++ b/Release/src/http/common/http_msg.cpp @@ -998,7 +998,8 @@ details::_http_request::_http_request(http::method mtd) : m_method(std::move(mtd)), m_initiated_response(0), m_server_context(), - m_cancellationToken(pplx::cancellation_token::none()) + m_cancellationToken(pplx::cancellation_token::none()), + m_http_version(http::http_version{0, 0}) { if(m_method.empty()) { @@ -1009,10 +1010,15 @@ details::_http_request::_http_request(http::method mtd) details::_http_request::_http_request(std::unique_ptr server_context) : m_initiated_response(0), m_server_context(std::move(server_context)), - m_cancellationToken(pplx::cancellation_token::none()) + m_cancellationToken(pplx::cancellation_token::none()), + m_http_version(http::http_version{0, 0}) { } +const http_version http_versions::HTTP_0_9 = { 0, 9 }; +const http_version http_versions::HTTP_1_0 = { 1, 0 }; +const http_version http_versions::HTTP_1_1 = { 1, 1 }; + #define _METHODS #define DAT(a,b) const method methods::a = b; #include "cpprest/details/http_constants.dat" diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 3fadebb03b..1a28a3ce6d 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -657,14 +657,32 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys // Get the version std::string http_version = http_path_and_version.substr(http_path_and_version.size() - VersionPortionSize + 1, VersionPortionSize - 2); + + auto m_request_impl = m_request._get_impl().get(); + web::http::http_version parsed_version = { 0, 0 }; + if (boost::starts_with(http_version, "HTTP/")) + { + std::istringstream version{ http_version.substr(5) }; + version >> parsed_version.major; + char dot; version >> dot; + version >> parsed_version.minor; + + m_request_impl->_set_http_version(parsed_version); + } + // if HTTP version is 1.0 then disable pipelining - if (http_version == "HTTP/1.0") + if (parsed_version == web::http::http_versions::HTTP_1_0) { m_close = true; } // Get the remote IP address - m_request._get_impl()->_set_remote_address(utility::conversions::to_string_t(m_socket->remote_endpoint().address().to_string())); + boost::system::error_code socket_ec; + auto endpoint = m_socket->remote_endpoint(socket_ec); + if (!socket_ec) + { + m_request._get_impl()->_set_remote_address(utility::conversions::to_string_t(endpoint.address().to_string())); + } return handle_headers(); } diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp index 9a0e257ef7..7d3cea203c 100644 --- a/Release/src/http/listener/http_server_httpsys.cpp +++ b/Release/src/http/listener/http_server_httpsys.cpp @@ -560,6 +560,8 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD m_msg.set_method(parse_request_method(m_request)); parse_http_headers(m_request->Headers, m_msg.headers()); + m_msg._get_impl()->_set_http_version({ (uint8_t)m_request->Version.MajorVersion, (uint8_t)m_request->Version.MinorVersion }); + // Retrieve the remote IP address std::vector remoteAddressBuffer(50); diff --git a/Release/tests/functional/http/listener/request_handler_tests.cpp b/Release/tests/functional/http/listener/request_handler_tests.cpp index 33f7d0ea85..3a1e135b13 100644 --- a/Release/tests/functional/http/listener/request_handler_tests.cpp +++ b/Release/tests/functional/http/listener/request_handler_tests.cpp @@ -448,6 +448,39 @@ TEST_FIXTURE(uri_address, test_leaks) listener.close().wait(); } +TEST_FIXTURE(uri_address, http_version) +{ + http_listener listener(U("http://localhost:45678/path1")); + listener.open().wait(); + + test_http_client::scoped_client client(U("http://localhost:45678/")); + test_http_client * p_client = client.client(); + + volatile unsigned long requestCount = 0; + + listener.support(methods::GET, [&requestCount](http_request request) + { + const auto& httpVersion = request.http_version(); + + // All clients currently use HTTP/1.1 + VERIFY_IS_TRUE(httpVersion == http_versions::HTTP_1_1); + + os_utilities::interlocked_increment(&requestCount); + request.reply(status_codes::NoContent); + }); + + // Send a request to the listener + VERIFY_ARE_EQUAL(0, p_client->request(methods::GET, U("/path1"))); + + p_client->next_response().then([](test_response *p_response) + { + http_asserts::assert_test_response_equals(p_response, status_codes::NoContent); + }).wait(); + + VERIFY_IS_TRUE(requestCount >= 1); + listener.close().wait(); +} + TEST_FIXTURE(uri_address, remote_address) { http_listener listener(U("http://localhost:45678/path1")); @@ -460,7 +493,7 @@ TEST_FIXTURE(uri_address, remote_address) listener.support(methods::GET, [&requestCount](http_request request) { - const string_t& remoteAddr = request.get_remote_address(); + const string_t& remoteAddr = request.remote_address(); const string_t& localhost4 = string_t(U("127.0.0.1")); const string_t& localhost6 = string_t(U("::1")); From a159e4e7b5eb640a0a09eca8decff32827cb40be Mon Sep 17 00:00:00 2001 From: Gareth Sylvester-Bradley <31761158+garethsb-sony@users.noreply.github.com> Date: Thu, 25 Jan 2018 21:18:25 +0000 Subject: [PATCH 201/438] Fix VS2013 compilation errors (#678) * Revert explicitly defaulted move constructors and assignment operators (part of commit b0634729ae3ece059f5d727e6176f9bf8b9a0e77) to restore compatibility with VS2013 (fix #674) * Simplify and make consistent use of member typedefs in basic_istream and the type_parser hierarchy, which also fixes #675 * Restore EOL: Unix (seems to have been EOL: Mixed at commit 3e8dcf5b574fa7f23920de3166e03fee5bf5aae1) * Add comments explicitly indicating suboptimal code for VS2013 compat --- Release/include/cpprest/base_uri.h | 45 ++++++++++- Release/include/cpprest/streams.h | 123 ++++++++++++++++++----------- 2 files changed, 117 insertions(+), 51 deletions(-) diff --git a/Release/include/cpprest/base_uri.h b/Release/include/cpprest/base_uri.h index 1d2874a41b..b5fc8fcfd0 100644 --- a/Release/include/cpprest/base_uri.h +++ b/Release/include/cpprest/base_uri.h @@ -32,8 +32,32 @@ namespace web { uri_components(const uri_components &other) = default; uri_components & operator=(const uri_components &other) = default; - uri_components(uri_components &&other) = default; - uri_components & operator=(uri_components &&other) = default; + // This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped. + uri_components(uri_components &&other) CPPREST_NOEXCEPT : + m_scheme(std::move(other.m_scheme)), + m_host(std::move(other.m_host)), + m_user_info(std::move(other.m_user_info)), + m_path(std::move(other.m_path)), + m_query(std::move(other.m_query)), + m_fragment(std::move(other.m_fragment)), + m_port(other.m_port) + {} + + // This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped. + uri_components & operator=(uri_components &&other) CPPREST_NOEXCEPT + { + if (this != &other) + { + m_scheme = std::move(other.m_scheme); + m_host = std::move(other.m_host); + m_user_info = std::move(other.m_user_info); + m_path = std::move(other.m_path); + m_query = std::move(other.m_query); + m_fragment = std::move(other.m_fragment); + m_port = other.m_port; + } + return *this; + } _ASYNCRTIMP utility::string_t join(); @@ -195,12 +219,25 @@ namespace web { /// /// Move constructor. /// - uri(uri &&other) = default; + // This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped. + uri(uri &&other) CPPREST_NOEXCEPT : + m_uri(std::move(other.m_uri)), + m_components(std::move(other.m_components)) + {} /// /// Move assignment operator /// - uri & operator=(uri &&other) = default; + // This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped. + uri & operator=(uri &&other) CPPREST_NOEXCEPT + { + if (this != &other) + { + m_uri = std::move(other.m_uri); + m_components = std::move(other.m_components); + } + return *this; + } /// /// Get the scheme component of the URI as an encoded string. diff --git a/Release/include/cpprest/streams.h b/Release/include/cpprest/streams.h index 60d5504e78..0903713497 100644 --- a/Release/include/cpprest/streams.h +++ b/Release/include/cpprest/streams.h @@ -24,7 +24,7 @@ namespace Concurrency { namespace streams template class basic_istream; namespace details { - template + template class basic_ostream_helper { public: @@ -95,8 +95,7 @@ namespace Concurrency { namespace streams class basic_ostream { public: - - typedef Concurrency::streams::char_traits traits; + typedef char_traits traits; typedef typename traits::int_type int_type; typedef typename traits::pos_type pos_type; typedef typename traits::off_type off_type; @@ -480,7 +479,8 @@ namespace Concurrency { namespace streams class _type_parser_base { public: - typedef typename ::concurrency::streams::char_traits::int_type int_type; + typedef char_traits traits; + typedef typename traits::int_type int_type; _type_parser_base() { } @@ -560,7 +560,7 @@ namespace Concurrency { namespace streams public: typedef char_traits traits; - typedef typename char_traits::int_type int_type; + typedef typename traits::int_type int_type; typedef typename traits::pos_type pos_type; typedef typename traits::off_type off_type; @@ -769,7 +769,7 @@ namespace Concurrency { namespace streams // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations. auto buffer = helper()->m_buffer; - int_type req_async = ::concurrency::streams::char_traits::requires_async(); + int_type req_async = traits::requires_async(); std::shared_ptr<_read_helper> _locals = std::make_shared<_read_helper>(); @@ -785,7 +785,7 @@ namespace Concurrency { namespace streams auto update = [=](int_type ch) mutable { - if (ch == ::concurrency::streams::char_traits::eof()) return false; + if (ch == traits::eof()) return false; if (ch == delim) return false; _locals->outbuf[_locals->write_pos] = static_cast(ch); @@ -841,7 +841,7 @@ namespace Concurrency { namespace streams // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations. concurrency::streams::streambuf buffer = helper()->m_buffer; - typename concurrency::streams::char_traits::int_type req_async = concurrency::streams::char_traits::requires_async(); + int_type req_async = traits::requires_async(); std::shared_ptr<_read_helper> _locals = std::make_shared<_read_helper>(); @@ -855,9 +855,9 @@ namespace Concurrency { namespace streams }); }; - auto update = [=](typename concurrency::streams::char_traits::int_type ch) mutable + auto update = [=](int_type ch) mutable { - if (ch == concurrency::streams::char_traits::eof()) return false; + if (ch == traits::eof()) return false; if (ch == '\n') return false; if (ch == '\r') { @@ -878,13 +878,12 @@ namespace Concurrency { namespace streams return true; }; - auto update_after_cr = [=] (typename concurrency::streams::char_traits::int_type ch) mutable -> pplx::task + auto update_after_cr = [=] (int_type ch) mutable -> pplx::task { - if (ch == concurrency::streams::char_traits::eof()) return pplx::task_from_result(false); + if (ch == traits::eof()) return pplx::task_from_result(false); if (ch == '\n') { - return buffer.bumpc().then([]( - typename concurrency::streams::char_traits::int_type) { return false; }); + return buffer.bumpc().then([](int_type) { return false; }); } return pplx::task_from_result(false); }; @@ -893,7 +892,7 @@ namespace Concurrency { namespace streams { while ( buffer.in_avail() > 0 ) { - typename concurrency::streams::char_traits::int_type ch; + int_type ch; if (_locals->saw_CR) { @@ -1123,9 +1122,9 @@ namespace Concurrency { namespace streams typedef basic_istream wistream; template -pplx::task concurrency::streams::_type_parser_base::_skip_whitespace(streams::streambuf buffer) +pplx::task _type_parser_base::_skip_whitespace(streams::streambuf buffer) { - int_type req_async = concurrency::streams::char_traits::requires_async(); + int_type req_async = traits::requires_async(); auto update = [=] (int_type ch) mutable { @@ -1168,7 +1167,7 @@ pplx::task concurrency::streams::_type_parser_base::_skip_whites template template -pplx::task concurrency::streams::_type_parser_base::_parse_input( +pplx::task _type_parser_base::_parse_input( concurrency::streams::streambuf buffer, AcceptFunctor accept_character, ExtractFunctor extract) @@ -1178,7 +1177,7 @@ pplx::task concurrency::streams::_type_parser_base::_parse auto update = [=] (pplx::task op) -> pplx::task { int_type ch = op.get(); - if (ch == concurrency::streams::char_traits::eof()) return pplx::task_from_result(false); + if (ch == traits::eof()) return pplx::task_from_result(false); bool accptd = accept_character(state, ch); if (!accptd) return pplx::task_from_result(false); @@ -1225,17 +1224,20 @@ pplx::task concurrency::streams::_type_parser_base::_parse template class type_parser> : public _type_parser_base { - typedef typename _type_parser_base::int_type int_type; + typedef _type_parser_base base; public: + typedef typename base::traits traits; + typedef typename base::int_type int_type; + static pplx::task parse(streams::streambuf buffer) { - return concurrency::streams::_type_parser_base::template _parse_input, std::string>(buffer, _accept_char, _extract_result); + return base::template _parse_input, std::string>(buffer, _accept_char, _extract_result); } private: static bool _accept_char(std::shared_ptr> state, int_type ch) { - if ( ch == concurrency::streams::char_traits::eof() || isspace(ch)) return false; + if ( ch == traits::eof() || isspace(ch)) return false; state->push_back(CharType(ch)); return true; } @@ -1248,11 +1250,14 @@ class type_parser> : public _type_parser_ba template class type_parser : public _type_parser_base { + typedef _type_parser_base base; public: - typedef typename _type_parser_base::int_type int_type; + typedef typename base::traits traits; + typedef typename base::int_type int_type; + static pplx::task parse(streams::streambuf buffer) { - return _type_parser_base::template _parse_input<_int64_state, int64_t>(buffer, _accept_char, _extract_result); + return base::template _parse_input<_int64_state, int64_t>(buffer, _accept_char, _extract_result); } private: struct _int64_state @@ -1266,7 +1271,7 @@ class type_parser : public _type_parser_base static bool _accept_char(std::shared_ptr<_int64_state> state, int_type ch) { - if ( ch == concurrency::streams::char_traits::eof()) return false; + if ( ch == traits::eof()) return false; if ( state->minus == 0 ) { // OK to find a sign. @@ -1487,11 +1492,14 @@ static pplx::task _extract_result(std::shared_ptr<_double_state class type_parser : public _type_parser_base { + typedef _type_parser_base base; public: - typedef typename _type_parser_base::int_type int_type; + typedef typename base::traits traits; + typedef typename base::int_type int_type; + static pplx::task parse(streams::streambuf buffer) { - return _type_parser_base::template _parse_input<_double_state, double>(buffer, _accept_char, _extract_result); + return base::template _parse_input<_double_state, double>(buffer, _accept_char, _extract_result); } protected: }; @@ -1499,11 +1507,14 @@ class type_parser : public _type_parser_base template class type_parser : public _type_parser_base { + typedef _type_parser_base base; public: - typedef typename _type_parser_base::int_type int_type; + typedef typename base::traits traits; + typedef typename base::int_type int_type; + static pplx::task parse(streams::streambuf buffer) { - return _type_parser_base::template _parse_input<_double_state, float>(buffer, _accept_char, _extract_result); + return base::template _parse_input<_double_state, float>(buffer, _accept_char, _extract_result); } protected: }; @@ -1512,11 +1523,14 @@ class type_parser : public _type_parser_base template class type_parser : public _type_parser_base { + typedef _type_parser_base base; public: - typedef typename _type_parser_base::int_type int_type; + typedef typename base::traits traits; + typedef typename base::int_type int_type; + static pplx::task parse(streams::streambuf buffer) { - return _type_parser_base::template _parse_input<_uint64_state,uint64_t>(buffer, _accept_char, _extract_result); + return base::template _parse_input<_uint64_state,uint64_t>(buffer, _accept_char, _extract_result); } private: @@ -1552,11 +1566,14 @@ class type_parser : public _type_parser_base template class type_parser : public _type_parser_base { + typedef _type_parser_base base; public: - typedef typename _type_parser_base::int_type int_type; + typedef typename base::traits traits; + typedef typename base::int_type int_type; + static pplx::task parse(streams::streambuf buffer) { - return _type_parser_base::template _parse_input<_bool_state,bool>(buffer, _accept_char, _extract_result); + return base::template _parse_input<_bool_state,bool>(buffer, _accept_char, _extract_result); } private: struct _bool_state @@ -1626,11 +1643,14 @@ class type_parser : public _type_parser_base template class type_parser : public _type_parser_base { - typedef typename concurrency::streams::streambuf::int_type int_type; + typedef _type_parser_base base; public: + typedef typename base::traits traits; + typedef typename base::int_type int_type; + static pplx::task parse(streams::streambuf buffer) { - return _type_parser_base::_skip_whitespace(buffer).then( + return base::_skip_whitespace(buffer).then( [=](pplx::task op) -> pplx::task { op.wait(); @@ -1642,10 +1662,10 @@ class type_parser : public _type_parser_base { concurrency::streams::streambuf buf = buffer; return buf.bumpc().then( - [=](pplx::task::int_type> op) -> signed char + [=](pplx::task op) -> signed char { int_type val = op.get(); - if (val == concurrency::streams::char_traits::eof()) + if (val == traits::eof()) throw std::runtime_error("reached end-of-stream while constructing a value"); return static_cast(val); }); @@ -1655,11 +1675,14 @@ class type_parser : public _type_parser_base template class type_parser : public _type_parser_base { - typedef typename concurrency::streams::streambuf::int_type int_type; + typedef _type_parser_base base; public: + typedef typename base::traits traits; + typedef typename base::int_type int_type; + static pplx::task parse(streams::streambuf buffer) { - return _type_parser_base::_skip_whitespace(buffer).then( + return base::_skip_whitespace(buffer).then( [=](pplx::task op) -> pplx::task { op.wait(); @@ -1671,10 +1694,10 @@ class type_parser : public _type_parser_base { concurrency::streams::streambuf buf = buffer; return buf.bumpc().then( - [=](pplx::task::int_type> op) -> unsigned char + [=](pplx::task op) -> unsigned char { int_type val = op.get(); - if (val == concurrency::streams::char_traits::eof()) + if (val == traits::eof()) throw std::runtime_error("reached end-of-stream while constructing a value"); return static_cast(val); }); @@ -1684,11 +1707,14 @@ class type_parser : public _type_parser_base template class type_parser : public _type_parser_base { - typedef typename concurrency::streams::streambuf::int_type int_type; + typedef _type_parser_base base; public: + typedef typename base::traits traits; + typedef typename base::int_type int_type; + static pplx::task parse(streams::streambuf buffer) { - return _type_parser_base::_skip_whitespace(buffer).then( + return base::_skip_whitespace(buffer).then( [=](pplx::task op) -> pplx::task { op.wait(); @@ -1700,10 +1726,10 @@ class type_parser : public _type_parser_base { concurrency::streams::streambuf buf = buffer; return buf.bumpc().then( - [=](pplx::task::int_type> op) -> char + [=](pplx::task op) -> char { int_type val = op.get(); - if (val == concurrency::streams::char_traits::eof()) + if (val == traits::eof()) throw std::runtime_error("reached end-of-stream while constructing a value"); return char(val); }); @@ -1714,8 +1740,11 @@ class type_parser : public _type_parser_base template class type_parser>> : public _type_parser_base { - typedef typename concurrency::streams::streambuf::int_type int_type; + typedef _type_parser_base base; public: + typedef typename base::traits traits; + typedef typename base::int_type int_type; + static pplx::task parse(streams::streambuf buffer) { return _parse_input,std::basic_string>(buffer, _accept_char, _extract_result); @@ -1738,4 +1767,4 @@ class type_parser Date: Fri, 26 Jan 2018 18:14:50 +0000 Subject: [PATCH 202/438] Fix a regression in parsing an HTTP-Version string (#677) * Fix a regression in parsing an HTTP-Version string, pulling the parsing code out into http_version::from_string; add extra unit tests * Restore EOL: Unix * Remove dependency on locale from http_version member functions. Prefer UTF-8. --- Release/include/cpprest/http_msg.h | 11 +++++++ Release/src/http/common/http_msg.cpp | 31 ++++++++++++++++++- .../src/http/listener/http_server_asio.cpp | 12 ++----- .../http/listener/request_handler_tests.cpp | 23 ++++++++++++++ 4 files changed, 66 insertions(+), 11 deletions(-) diff --git a/Release/include/cpprest/http_msg.h b/Release/include/cpprest/http_msg.h index 6b49bc4960..00f58e1350 100644 --- a/Release/include/cpprest/http_msg.h +++ b/Release/include/cpprest/http_msg.h @@ -58,6 +58,17 @@ struct http_version inline bool operator>=(const http_version& other) const { return !(*this < other); } inline bool operator>(const http_version& other) const { return !(*this < other || *this == other); } inline bool operator<=(const http_version& other) const { return *this < other || *this == other; } + + /// + /// Creates http_version from an HTTP-Version string, "HTTP" "/" 1*DIGIT "." 1*DIGIT. + /// + /// Returns a http_version of {0, 0} if not successful. + static _ASYNCRTIMP http_version __cdecl from_string(const utility::string_t& http_version_string); + + /// + /// Returns the string representation of the http_version. + /// + _ASYNCRTIMP std::string to_utf8string() const; }; /// diff --git a/Release/src/http/common/http_msg.cpp b/Release/src/http/common/http_msg.cpp index 5e6eb73386..459aff5609 100644 --- a/Release/src/http/common/http_msg.cpp +++ b/Release/src/http/common/http_msg.cpp @@ -254,6 +254,35 @@ void parse_headers_string(_Inout_z_ utf16char *headersStr, http_headers &headers } +http_version __cdecl http_version::from_string(const utility::string_t& http_version_string) +{ + utility::istringstream_t str(http_version_string); + str.imbue(std::locale::classic()); + + utility::string_t http; std::getline(str, http, _XPLATSTR('/')); + unsigned int major = 0; str >> major; + utility::char_t dot = _XPLATSTR('\0'); str >> dot; + unsigned int minor = 0; str >> minor; + + // check no failure, fully consumed, and correct fixed text + if (!str.fail() && str.eof() && _XPLATSTR("HTTP") == http && _XPLATSTR('.') == dot) + { + return{ (uint8_t)major, (uint8_t)minor }; + } + return{ 0, 0 }; +} + +std::string http_version::to_utf8string() const +{ + std::string ret; + ret.reserve(8); + ret.append("HTTP/"); + ret.append(std::to_string(static_cast(major))); + ret.append("."); + ret.append(std::to_string(static_cast(minor))); + return ret; +} + static const utility::char_t * stream_was_set_explicitly = _XPLATSTR("A stream was set on the message and extraction is not possible"); static const utility::char_t * unsupported_charset = _XPLATSTR("Charset must be iso-8859-1, utf-8, utf-16, utf-16le, or utf-16be to be extracted."); @@ -1052,4 +1081,4 @@ const http_version http_versions::HTTP_1_1 = { 1, 1 }; #undef DAT #endif }} // namespace web::http - + diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 1a28a3ce6d..e7f9232816 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -659,16 +659,8 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys std::string http_version = http_path_and_version.substr(http_path_and_version.size() - VersionPortionSize + 1, VersionPortionSize - 2); auto m_request_impl = m_request._get_impl().get(); - web::http::http_version parsed_version = { 0, 0 }; - if (boost::starts_with(http_version, "HTTP/")) - { - std::istringstream version{ http_version.substr(5) }; - version >> parsed_version.major; - char dot; version >> dot; - version >> parsed_version.minor; - - m_request_impl->_set_http_version(parsed_version); - } + web::http::http_version parsed_version = web::http::http_version::from_string(utility::conversions::to_string_t(http_version)); + m_request_impl->_set_http_version(parsed_version); // if HTTP version is 1.0 then disable pipelining if (parsed_version == web::http::http_versions::HTTP_1_0) diff --git a/Release/tests/functional/http/listener/request_handler_tests.cpp b/Release/tests/functional/http/listener/request_handler_tests.cpp index 3a1e135b13..269a0e23b0 100644 --- a/Release/tests/functional/http/listener/request_handler_tests.cpp +++ b/Release/tests/functional/http/listener/request_handler_tests.cpp @@ -450,6 +450,29 @@ TEST_FIXTURE(uri_address, test_leaks) TEST_FIXTURE(uri_address, http_version) { + // formatting should succeed + VERIFY_IS_TRUE("HTTP/0.9" == http_versions::HTTP_0_9.to_utf8string()); + VERIFY_IS_TRUE("HTTP/1.0" == http_versions::HTTP_1_0.to_utf8string()); + VERIFY_IS_TRUE("HTTP/1.1" == http_versions::HTTP_1_1.to_utf8string()); + VERIFY_IS_TRUE("HTTP/12.3" == (http_version{ 12, 3 }).to_utf8string()); + // parsing should succeed + VERIFY_IS_TRUE(http_version::from_string(U("HTTP/0.9")) == http_versions::HTTP_0_9); + VERIFY_IS_TRUE(http_version::from_string(U("HTTP/1.0")) == http_versions::HTTP_1_0); + VERIFY_IS_TRUE(http_version::from_string(U("HTTP/1.1")) == http_versions::HTTP_1_1); + VERIFY_IS_TRUE((http_version::from_string(U("HTTP/12.3")) == http_version{ 12, 3 })); + // parsing should fail + http_version unknown = { 0, 0 }; + VERIFY_IS_TRUE(http_version::from_string(U("http/12.3")) == unknown); + VERIFY_IS_TRUE(http_version::from_string(U("HTTP/12.3foo")) == unknown); + VERIFY_IS_TRUE(http_version::from_string(U("HTTP/12.")) == unknown); + VERIFY_IS_TRUE(http_version::from_string(U("HTTP/12")) == unknown); + VERIFY_IS_TRUE(http_version::from_string(U("HTTP/.3")) == unknown); + VERIFY_IS_TRUE(http_version::from_string(U("HTTP/")) == unknown); + VERIFY_IS_TRUE(http_version::from_string(U("HTTP")) == unknown); + VERIFY_IS_TRUE(http_version::from_string(U("HTTP")) == unknown); + VERIFY_IS_TRUE(http_version::from_string(U("foo")) == unknown); + VERIFY_IS_TRUE(http_version::from_string(U("")) == unknown); + http_listener listener(U("http://localhost:45678/path1")); listener.open().wait(); From 1e4717e5aefb080bfc3edd3b9d6ca6e2546c0111 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Fri, 26 Jan 2018 11:52:35 -0800 Subject: [PATCH 203/438] Convert http_versions::from_string to use UTF-8 --- Release/include/cpprest/http_msg.h | 2 +- Release/src/http/common/http_msg.cpp | 10 +++---- .../http/listener/request_handler_tests.cpp | 28 +++++++++---------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Release/include/cpprest/http_msg.h b/Release/include/cpprest/http_msg.h index 00f58e1350..b85e98ff42 100644 --- a/Release/include/cpprest/http_msg.h +++ b/Release/include/cpprest/http_msg.h @@ -63,7 +63,7 @@ struct http_version /// Creates http_version from an HTTP-Version string, "HTTP" "/" 1*DIGIT "." 1*DIGIT. /// /// Returns a http_version of {0, 0} if not successful. - static _ASYNCRTIMP http_version __cdecl from_string(const utility::string_t& http_version_string); + static _ASYNCRTIMP http_version __cdecl from_string(const std::string& http_version_string); /// /// Returns the string representation of the http_version. diff --git a/Release/src/http/common/http_msg.cpp b/Release/src/http/common/http_msg.cpp index 459aff5609..ad2c70e9d7 100644 --- a/Release/src/http/common/http_msg.cpp +++ b/Release/src/http/common/http_msg.cpp @@ -254,18 +254,18 @@ void parse_headers_string(_Inout_z_ utf16char *headersStr, http_headers &headers } -http_version __cdecl http_version::from_string(const utility::string_t& http_version_string) +http_version __cdecl http_version::from_string(const std::string& http_version_string) { - utility::istringstream_t str(http_version_string); + std::stringstream str(http_version_string); str.imbue(std::locale::classic()); - utility::string_t http; std::getline(str, http, _XPLATSTR('/')); + std::string http; std::getline(str, http, '/'); unsigned int major = 0; str >> major; - utility::char_t dot = _XPLATSTR('\0'); str >> dot; + char dot = '\0'; str >> dot; unsigned int minor = 0; str >> minor; // check no failure, fully consumed, and correct fixed text - if (!str.fail() && str.eof() && _XPLATSTR("HTTP") == http && _XPLATSTR('.') == dot) + if (!str.fail() && str.eof() && "HTTP" == http && '.' == dot) { return{ (uint8_t)major, (uint8_t)minor }; } diff --git a/Release/tests/functional/http/listener/request_handler_tests.cpp b/Release/tests/functional/http/listener/request_handler_tests.cpp index 269a0e23b0..74137193ae 100644 --- a/Release/tests/functional/http/listener/request_handler_tests.cpp +++ b/Release/tests/functional/http/listener/request_handler_tests.cpp @@ -456,22 +456,22 @@ TEST_FIXTURE(uri_address, http_version) VERIFY_IS_TRUE("HTTP/1.1" == http_versions::HTTP_1_1.to_utf8string()); VERIFY_IS_TRUE("HTTP/12.3" == (http_version{ 12, 3 }).to_utf8string()); // parsing should succeed - VERIFY_IS_TRUE(http_version::from_string(U("HTTP/0.9")) == http_versions::HTTP_0_9); - VERIFY_IS_TRUE(http_version::from_string(U("HTTP/1.0")) == http_versions::HTTP_1_0); - VERIFY_IS_TRUE(http_version::from_string(U("HTTP/1.1")) == http_versions::HTTP_1_1); - VERIFY_IS_TRUE((http_version::from_string(U("HTTP/12.3")) == http_version{ 12, 3 })); + VERIFY_IS_TRUE(http_version::from_string("HTTP/0.9") == http_versions::HTTP_0_9); + VERIFY_IS_TRUE(http_version::from_string("HTTP/1.0") == http_versions::HTTP_1_0); + VERIFY_IS_TRUE(http_version::from_string("HTTP/1.1") == http_versions::HTTP_1_1); + VERIFY_IS_TRUE((http_version::from_string("HTTP/12.3") == http_version{ 12, 3 })); // parsing should fail http_version unknown = { 0, 0 }; - VERIFY_IS_TRUE(http_version::from_string(U("http/12.3")) == unknown); - VERIFY_IS_TRUE(http_version::from_string(U("HTTP/12.3foo")) == unknown); - VERIFY_IS_TRUE(http_version::from_string(U("HTTP/12.")) == unknown); - VERIFY_IS_TRUE(http_version::from_string(U("HTTP/12")) == unknown); - VERIFY_IS_TRUE(http_version::from_string(U("HTTP/.3")) == unknown); - VERIFY_IS_TRUE(http_version::from_string(U("HTTP/")) == unknown); - VERIFY_IS_TRUE(http_version::from_string(U("HTTP")) == unknown); - VERIFY_IS_TRUE(http_version::from_string(U("HTTP")) == unknown); - VERIFY_IS_TRUE(http_version::from_string(U("foo")) == unknown); - VERIFY_IS_TRUE(http_version::from_string(U("")) == unknown); + VERIFY_IS_TRUE(http_version::from_string("http/12.3") == unknown); + VERIFY_IS_TRUE(http_version::from_string("HTTP/12.3foo") == unknown); + VERIFY_IS_TRUE(http_version::from_string("HTTP/12.") == unknown); + VERIFY_IS_TRUE(http_version::from_string("HTTP/12") == unknown); + VERIFY_IS_TRUE(http_version::from_string("HTTP/.3") == unknown); + VERIFY_IS_TRUE(http_version::from_string("HTTP/") == unknown); + VERIFY_IS_TRUE(http_version::from_string("HTTP") == unknown); + VERIFY_IS_TRUE(http_version::from_string("HTTP") == unknown); + VERIFY_IS_TRUE(http_version::from_string("foo") == unknown); + VERIFY_IS_TRUE(http_version::from_string("") == unknown); http_listener listener(U("http://localhost:45678/path1")); listener.open().wait(); From fea848e2a77563cf2a6f28f8eab396fd6e787fbf Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 6 Feb 2018 15:23:26 -0800 Subject: [PATCH 204/438] Push version number to 2.10.2 --- Build/version.props | 2 +- Release/CMakeLists.txt | 2 +- Release/include/cpprest/version.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Build/version.props b/Build/version.props index cbf33ac51b..81b45b0316 100644 --- a/Build/version.props +++ b/Build/version.props @@ -4,7 +4,7 @@ cpprest 2 10 - 1 + 2 $(CppRestSDKVersionMajor)_$(CppRestSDKVersionMinor) $(CppRestSDKVersionMajor).$(CppRestSDKVersionMinor) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index ff775ed43e..3e0871c99c 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -11,7 +11,7 @@ endif() set(CPPREST_VERSION_MAJOR 2) set(CPPREST_VERSION_MINOR 10) -set(CPPREST_VERSION_REVISION 1) +set(CPPREST_VERSION_REVISION 2) enable_testing() diff --git a/Release/include/cpprest/version.h b/Release/include/cpprest/version.h index 2324dddddb..f3d9602e67 100644 --- a/Release/include/cpprest/version.h +++ b/Release/include/cpprest/version.h @@ -3,9 +3,9 @@ * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. * */ -#define CPPREST_VERSION_REVISION 1 +#define CPPREST_VERSION_REVISION 2 #define CPPREST_VERSION_MINOR 10 #define CPPREST_VERSION_MAJOR 2 #define CPPREST_VERSION (CPPREST_VERSION_MAJOR*100000+CPPREST_VERSION_MINOR*100+CPPREST_VERSION_REVISION) - + From f3ec72364703eab8ec8dfae41d50cb63c700933b Mon Sep 17 00:00:00 2001 From: Gareth Sylvester-Bradley <31761158+garethsb-sony@users.noreply.github.com> Date: Wed, 7 Feb 2018 18:22:41 +0000 Subject: [PATCH 205/438] Don't use the ``U()`` preprocessor macro in public headers (#693) * Don't use the ``U()`` preprocessor macro in public headers, in order to work when ``_TURN_OFF_PLATFORM_STRING`` is defined. * Add the explanation of the 'U' macro (and the use of '_TURN_OFF_PLATFORM_STRING') taken from the FAQ, close to its definition. --- Release/include/cpprest/details/basic_types.h | 3 +++ Release/include/cpprest/details/http_helpers.h | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Release/include/cpprest/details/basic_types.h b/Release/include/cpprest/details/basic_types.h index 36aad71b98..eadba01684 100644 --- a/Release/include/cpprest/details/basic_types.h +++ b/Release/include/cpprest/details/basic_types.h @@ -80,6 +80,9 @@ typedef std::stringstream stringstream_t; #endif // endif _UTF16_STRINGS #ifndef _TURN_OFF_PLATFORM_STRING +// The 'U' macro can be used to create a string or character literal of the platform type, i.e. utility::char_t. +// If you are using a library causing conflicts with 'U' macro, it can be turned off by defining the macro +// '_TURN_OFF_PLATFORM_STRING' before including the C++ REST SDK header files, and e.g. use '_XPLATSTR' instead. #define U(x) _XPLATSTR(x) #endif // !_TURN_OFF_PLATFORM_STRING diff --git a/Release/include/cpprest/details/http_helpers.h b/Release/include/cpprest/details/http_helpers.h index 05db40243a..2d2c1b6091 100644 --- a/Release/include/cpprest/details/http_helpers.h +++ b/Release/include/cpprest/details/http_helpers.h @@ -58,11 +58,11 @@ namespace details static compression_algorithm to_compression_algorithm(const utility::string_t& alg) { - if (U("gzip") == alg) + if (_XPLATSTR("gzip") == alg) { return compression_algorithm::gzip; } - else if (U("deflate") == alg) + else if (_XPLATSTR("deflate") == alg) { return compression_algorithm::deflate; } From 4cc30c7b631d426ebeb3f2d9bee94a3c3a20681f Mon Sep 17 00:00:00 2001 From: Marcin Buchwald Date: Fri, 16 Feb 2018 23:37:33 +0100 Subject: [PATCH 206/438] No need for ostringstream here (#700) --- Release/samples/BlackJack/BlackJack_Server/Dealer.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Release/samples/BlackJack/BlackJack_Server/Dealer.cpp b/Release/samples/BlackJack/BlackJack_Server/Dealer.cpp index b03cab9e26..7cb81d5bc2 100644 --- a/Release/samples/BlackJack/BlackJack_Server/Dealer.cpp +++ b/Release/samples/BlackJack/BlackJack_Server/Dealer.cpp @@ -47,12 +47,9 @@ BlackJackDealer::BlackJackDealer(utility::string_t url) : m_listener(url) m_listener.support(methods::PUT, std::bind(&BlackJackDealer::handle_put, this, std::placeholders::_1)); m_listener.support(methods::POST, std::bind(&BlackJackDealer::handle_post, this, std::placeholders::_1)); m_listener.support(methods::DEL, std::bind(&BlackJackDealer::handle_delete, this, std::placeholders::_1)); - - utility::ostringstream_t nextIdString; - nextIdString << nextId; std::shared_ptr tbl = std::make_shared(nextId, 8, 6); - s_tables[nextIdString.str()] = tbl; + s_tables[conversions::to_string_t(std::to_string(nextId))] = tbl; nextId += 1; } From b024470efc6b12f0bba82d825cc487c980beac13 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 22 Feb 2018 12:21:56 +0100 Subject: [PATCH 207/438] Fix XML in comment (#705) --- Release/include/cpprest/json.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/include/cpprest/json.h b/Release/include/cpprest/json.h index f4987f5c21..07c5450243 100644 --- a/Release/include/cpprest/json.h +++ b/Release/include/cpprest/json.h @@ -266,7 +266,7 @@ namespace json /// /// This overload has O(n) performance because it tries to determine if /// specified string has characters that should be properly escaped in JSON. - /// + /// static _ASYNCRTIMP value __cdecl string(utility::string_t value); /// From e0d42b5d4278aac0b4d89f2bb5177b7bdaccba70 Mon Sep 17 00:00:00 2001 From: Gareth Sylvester-Bradley <31761158+garethsb-sony@users.noreply.github.com> Date: Fri, 27 Apr 2018 11:42:43 +0100 Subject: [PATCH 208/438] Fix compilation failure with ``CPPREST_FORCE_PPLX=1`` (resolves #734) (#746) * Make sure internal _do_while is in the same namespace as other pplx tasks implementation details (resolves #734) * Reformat astreambuf.h line endings --- Release/include/cpprest/astreambuf.h | 14 +++++++++++--- Release/include/cpprest/streams.h | 10 +++++----- Release/tests/functional/streams/istream_tests.cpp | 2 +- .../tests/functional/streams/memstream_tests.cpp | 14 +++++++------- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Release/include/cpprest/astreambuf.h b/Release/include/cpprest/astreambuf.h index 642f0738dd..baff9a934d 100644 --- a/Release/include/cpprest/astreambuf.h +++ b/Release/include/cpprest/astreambuf.h @@ -22,7 +22,11 @@ #include "cpprest/details/basic_types.h" #include "cpprest/asyncrt_utils.h" -namespace Concurrency +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX +namespace Concurrency // since namespace pplx = Concurrency +#else +namespace pplx +#endif { namespace details { @@ -32,12 +36,16 @@ namespace Concurrency pplx::task first = func(); return first.then([=](bool guard) -> pplx::task { if (guard) - return Concurrency::details::_do_while(func); + return pplx::details::_do_while(func); else return first; }); } } +} + +namespace Concurrency +{ /// Library for asynchronous streams. namespace streams @@ -1201,4 +1209,4 @@ namespace streams }} - + diff --git a/Release/include/cpprest/streams.h b/Release/include/cpprest/streams.h index 0903713497..75deb8fc59 100644 --- a/Release/include/cpprest/streams.h +++ b/Release/include/cpprest/streams.h @@ -801,7 +801,7 @@ namespace Concurrency { namespace streams return true; }; - auto loop = Concurrency::details::_do_while([=]() mutable -> pplx::task + auto loop = pplx::details::_do_while([=]() mutable -> pplx::task { while (buffer.in_avail() > 0) { @@ -888,7 +888,7 @@ namespace Concurrency { namespace streams return pplx::task_from_result(false); }; - auto loop = Concurrency::details::_do_while([=]() mutable -> pplx::task + auto loop = pplx::details::_do_while([=]() mutable -> pplx::task { while ( buffer.in_avail() > 0 ) { @@ -968,7 +968,7 @@ namespace Concurrency { namespace streams }); }; - auto loop = Concurrency::details::_do_while(copy_to_target); + auto loop = pplx::details::_do_while(copy_to_target); return loop.then([=](bool) mutable -> size_t { @@ -1142,7 +1142,7 @@ pplx::task _type_parser_base::_skip_whitespace(streams::streambu return false; }; - auto loop = Concurrency::details::_do_while([=]() mutable -> pplx::task + auto loop = pplx::details::_do_while([=]() mutable -> pplx::task { while (buffer.in_avail() > 0) { @@ -1217,7 +1217,7 @@ pplx::task _type_parser_base::_parse_input( return _skip_whitespace(buffer).then([=](pplx::task op) -> pplx::task { op.wait(); - return Concurrency::details::_do_while(peek_char).then(finish); + return pplx::details::_do_while(peek_char).then(finish); }); } diff --git a/Release/tests/functional/streams/istream_tests.cpp b/Release/tests/functional/streams/istream_tests.cpp index 63995fc8c3..db12390c57 100644 --- a/Release/tests/functional/streams/istream_tests.cpp +++ b/Release/tests/functional/streams/istream_tests.cpp @@ -714,7 +714,7 @@ TEST(fstream_read_to_end_3) else return pplx::task_from_result(false); }; - Concurrency::details::_do_while([=]()-> pplx::task { + pplx::details::_do_while([=]()-> pplx::task { return stream.read().then(lambda1); }).wait(); diff --git a/Release/tests/functional/streams/memstream_tests.cpp b/Release/tests/functional/streams/memstream_tests.cpp index 1e20facf3e..5395cf2cf7 100644 --- a/Release/tests/functional/streams/memstream_tests.cpp +++ b/Release/tests/functional/streams/memstream_tests.cpp @@ -48,7 +48,7 @@ void streambuf_putc(StreamBufferType& wbuf) size_t count = 10; auto seg2 = [&count](typename StreamBufferType::int_type ) { return (--count > 0); }; auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putc(s[0]).then(seg2); }; - Concurrency::details::_do_while(seg1).wait(); + pplx::details::_do_while(seg1).wait(); VERIFY_ARE_EQUAL(s.size() + 10, wbuf.in_avail()); @@ -83,7 +83,7 @@ void streambuf_putc(concurrency::streams::rawptr_buffer& wbuf) size_t count = 10; auto seg2 = [&count](typename StreamBufferType::int_type ) { return (--count > 0); }; auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putc(s[0]).then(seg2); }; - Concurrency::details::_do_while(seg1).wait(); + pplx::details::_do_while(seg1).wait(); VERIFY_ARE_EQUAL(s.size() + 10, wbuf.block().size()); @@ -119,7 +119,7 @@ void streambuf_putc(concurrency::streams::container_buffer& wbuf size_t count = 10; auto seg2 = [&count](typename StreamBufferType::int_type ) { return (--count > 0); }; auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putc(s[0]).then(seg2); }; - Concurrency::details::_do_while(seg1).wait(); + pplx::details::_do_while(seg1).wait(); VERIFY_ARE_EQUAL(s.size() + 10, wbuf.collection().size()); @@ -150,7 +150,7 @@ void streambuf_putn(StreamBufferType& wbuf) int count = 10; auto seg2 = [&count](size_t ) { return (--count > 0); }; auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putn_nocopy(s.data(), s.size()).then(seg2); }; - Concurrency::details::_do_while(seg1).wait(); + pplx::details::_do_while(seg1).wait(); VERIFY_ARE_EQUAL(s.size() * 12, wbuf.in_avail()); wbuf.close().get(); @@ -180,7 +180,7 @@ void streambuf_putn(concurrency::streams::rawptr_buffer& wbuf) int count = 10; auto seg2 = [&count](size_t ) { return (--count > 0); }; auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putn_nocopy(s.data(), s.size()).then(seg2); }; - Concurrency::details::_do_while(seg1).wait(); + pplx::details::_do_while(seg1).wait(); wbuf.close().get(); VERIFY_IS_FALSE(wbuf.can_write()); @@ -209,7 +209,7 @@ void streambuf_putn(concurrency::streams::container_buffer& wbuf int count = 10; auto seg2 = [&count](size_t ) { return (--count > 0); }; auto seg1 = [&s,&wbuf, seg2]() { return wbuf.putn_nocopy(s.data(), s.size()).then(seg2); }; - Concurrency::details::_do_while(seg1).wait(); + pplx::details::_do_while(seg1).wait(); wbuf.close().get(); VERIFY_IS_FALSE(wbuf.can_write()); @@ -1935,7 +1935,7 @@ void IStreamTest11() auto seg2 = [&ch](int val) { return (val != -1) && (++ch <= 'z'); }; auto seg1 = [=,&ch,&rbuf]() { return rbuf.putc(ch).then(seg2); }; - Concurrency::details::_do_while(seg1).wait(); + pplx::details::_do_while(seg1).wait(); VERIFY_ARE_EQUAL(26u, rbuf.in_avail()); From 3439ea40412542ed3034670022db714f37abe9ae Mon Sep 17 00:00:00 2001 From: Gareth Sylvester-Bradley <31761158+garethsb-sony@users.noreply.github.com> Date: Fri, 27 Apr 2018 16:52:39 +0100 Subject: [PATCH 209/438] Fix to work with commit 1e4717e5aefb080bfc3edd3b9d6ca6e2546c0111 (#681) --- Release/src/http/listener/http_server_asio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index e7f9232816..78193fa3e2 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -659,7 +659,7 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys std::string http_version = http_path_and_version.substr(http_path_and_version.size() - VersionPortionSize + 1, VersionPortionSize - 2); auto m_request_impl = m_request._get_impl().get(); - web::http::http_version parsed_version = web::http::http_version::from_string(utility::conversions::to_string_t(http_version)); + web::http::http_version parsed_version = web::http::http_version::from_string(http_version); m_request_impl->_set_http_version(parsed_version); // if HTTP version is 1.0 then disable pipelining From 175d0ac77c11be53f3e66f85b5791e3a4d793500 Mon Sep 17 00:00:00 2001 From: VZ Date: Sun, 6 May 2018 01:52:15 +0200 Subject: [PATCH 210/438] Require at least CMake 3.1 due to use of target_sources (#752) target_sources() is only available since this version and this avoids CMake Error at src/CMakeLists.txt:92 (target_sources): Unknown CMake command "target_sources". when using CMake 3.0, for example. Closes #633. --- Release/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 3e0871c99c..5362d1cd9e 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -1,5 +1,5 @@ set(CMAKE_LEGACY_CYGWIN_WIN32 0) -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.1) if(POLICY CMP0042) cmake_policy(SET CMP0042 NEW) # use MACOSX_RPATH endif() From 68b0ddf52cf1d8364b64900e8cf1a0629f5d3bef Mon Sep 17 00:00:00 2001 From: Thomas Barnekov <37448419+tbarnekov@users.noreply.github.com> Date: Fri, 18 May 2018 04:53:21 +0200 Subject: [PATCH 211/438] Fixed issue with Automatic Proxy detection when using WPAD on Windows 8.1 or higher (#722) --- .../src/http/client/http_client_winhttp.cpp | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 1d17db5899..2417859956 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -431,37 +431,40 @@ class winhttp_client : public _http_client_communicator #ifndef CPPREST_TARGET_XP if (IsWindows8Point1OrGreater()) { + // Windows 8.1 and newer supports automatic proxy discovery and auto-fallback to IE proxy settings access_type = WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY; } - - // However, if it is not configured... - proxy_info proxyDefault; - if(!WinHttpGetDefaultProxyConfiguration(&proxyDefault) || - proxyDefault.dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY) + else { - // ... then try to fall back on the default WinINET proxy, as - // recommended for the desktop applications (if we're not - // running under a user account, the function below will just - // fail, so there is no real need to check for this explicitly) - if(WinHttpGetIEProxyConfigForCurrentUser(&proxyIE)) + // However, if it is not configured... + proxy_info proxyDefault; + if (!WinHttpGetDefaultProxyConfiguration(&proxyDefault) || + proxyDefault.dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY) { - if(proxyIE.fAutoDetect) - { - m_proxy_auto_config = true; - } - else if(proxyIE.lpszAutoConfigUrl) + // ... then try to fall back on the default WinINET proxy, as + // recommended for the desktop applications (if we're not + // running under a user account, the function below will just + // fail, so there is no real need to check for this explicitly) + if (WinHttpGetIEProxyConfigForCurrentUser(&proxyIE)) { - m_proxy_auto_config = true; - m_proxy_auto_config_url = proxyIE.lpszAutoConfigUrl; - } - else if(proxyIE.lpszProxy) - { - access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; - proxy_name = proxyIE.lpszProxy; - - if(proxyIE.lpszProxyBypass) + if (proxyIE.fAutoDetect) { - proxy_bypass = proxyIE.lpszProxyBypass; + m_proxy_auto_config = true; + } + else if (proxyIE.lpszAutoConfigUrl) + { + m_proxy_auto_config = true; + m_proxy_auto_config_url = proxyIE.lpszAutoConfigUrl; + } + else if (proxyIE.lpszProxy) + { + access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; + proxy_name = proxyIE.lpszProxy; + + if (proxyIE.lpszProxyBypass) + { + proxy_bypass = proxyIE.lpszProxyBypass; + } } } } @@ -1122,10 +1125,10 @@ class winhttp_client : public _http_client_communicator try { web::uri current_uri(get_request_url(http://github.com/hRequestHandle)); - is_redirect = p_request_context->m_request.absolute_uri().to_string() != current_uri.to_string(); + is_redirect = p_request_context->m_request.absolute_uri().to_string() != current_uri.to_string(); } catch (const std::exception&) {} - + // If we have been redirected, then WinHttp needs the proxy credentials again to make the next request leg (which may be on a different server) if (is_redirect || !p_request_context->m_proxy_authentication_tried) { From 81442344caac03d307131069876c02018b5d34e8 Mon Sep 17 00:00:00 2001 From: Robert Andrzejuk Date: Tue, 17 Jul 2018 22:33:38 +0200 Subject: [PATCH 212/438] Fix for compilation with MSVC permissive- (#809) Related Visual Studio issue: https://developercommunity.visualstudio.com/content/problem/238445/template-class-cant-access-protected-member-when-c.html Problem is with code compiling with /permissive-, so the template functions are affected by this issue. --- Release/include/cpprest/streams.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/include/cpprest/streams.h b/Release/include/cpprest/streams.h index 75deb8fc59..5a46c7f077 100644 --- a/Release/include/cpprest/streams.h +++ b/Release/include/cpprest/streams.h @@ -1747,7 +1747,7 @@ class type_parser parse(streams::streambuf buffer) { - return _parse_input,std::basic_string>(buffer, _accept_char, _extract_result); + return base::_parse_input,std::basic_string>(buffer, _accept_char, _extract_result); } private: From 3839196d551abc79191be81e86bcfaa31dba80eb Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 17 Jul 2018 13:34:38 -0700 Subject: [PATCH 213/438] Fix test issues under /permissive- --- Release/include/cpprest/streams.h | 3 ++- Release/tests/functional/websockets/CMakeLists.txt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Release/include/cpprest/streams.h b/Release/include/cpprest/streams.h index 5a46c7f077..cb7cd4d0ea 100644 --- a/Release/include/cpprest/streams.h +++ b/Release/include/cpprest/streams.h @@ -577,7 +577,8 @@ namespace Concurrency { namespace streams /// The data type of the basic element of the stream. /// /// A stream buffer. - basic_istream(streams::streambuf buffer) : m_helper(std::make_shared>(buffer)) + template + basic_istream(streams::streambuf buffer) : m_helper(std::make_shared>(std::move(buffer))) { _verify_and_throw(details::_in_streambuf_msg); } diff --git a/Release/tests/functional/websockets/CMakeLists.txt b/Release/tests/functional/websockets/CMakeLists.txt index 889a4e0484..c8efb77ca1 100644 --- a/Release/tests/functional/websockets/CMakeLists.txt +++ b/Release/tests/functional/websockets/CMakeLists.txt @@ -31,4 +31,5 @@ if (NOT CPPREST_EXCLUDE_WEBSOCKETS) if(NOT TEST_LIBRARY_TARGET_TYPE STREQUAL "OBJECT") target_link_libraries(websocketsclient_test PRIVATE websockettest_utilities) endif() + target_include_directories(websocketsclient_test PRIVATE utilities) endif() From 1d8be69c58e474e891084c15a35ad6c153649834 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Fri, 20 Jul 2018 16:09:48 -0700 Subject: [PATCH 214/438] Add root CMakeLists.txt --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..c66d502345 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.0) +project(cpprestsdk-root NONE) + +add_subdirectory(Release) From 48189bd460e08919befffe18cb239ecd8e5ad228 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 11 Jul 2018 03:27:33 -0700 Subject: [PATCH 215/438] Do not fail on unrecognized content encoding (such as chunked) when compression is enabled. --- .../include/cpprest/details/http_helpers.h | 2 + Release/src/http/client/http_client.cpp | 38 ++++++++++ Release/src/http/client/http_client_asio.cpp | 26 ++----- Release/src/http/client/http_client_impl.h | 9 +++ .../src/http/client/http_client_winhttp.cpp | 37 +++------- .../http/client/request_helper_tests.cpp | 72 +++++++++++++++++++ 6 files changed, 138 insertions(+), 46 deletions(-) diff --git a/Release/include/cpprest/details/http_helpers.h b/Release/include/cpprest/details/http_helpers.h index 2d2c1b6091..596ac9efaa 100644 --- a/Release/include/cpprest/details/http_helpers.h +++ b/Release/include/cpprest/details/http_helpers.h @@ -70,6 +70,8 @@ namespace details return compression_algorithm::invalid; } + static utility::string_t known_algorithms() { return _XPLATSTR("deflate, gzip"); } + _ASYNCRTIMP static bool __cdecl is_supported(); _ASYNCRTIMP stream_decompressor(compression_algorithm alg); diff --git a/Release/src/http/client/http_client.cpp b/Release/src/http/client/http_client.cpp index 164bec3f48..fdaca8f151 100644 --- a/Release/src/http/client/http_client.cpp +++ b/Release/src/http/client/http_client.cpp @@ -96,6 +96,44 @@ void request_context::report_exception(std::exception_ptr exceptionPtr) finish(); } +bool request_context::handle_content_encoding_compression() +{ + if (web::http::details::compression::stream_decompressor::is_supported() && m_http_client->client_config().request_compressed_response()) + { + // If the response body is compressed we will read the encoding header and create a decompressor object which will later decompress the body + auto&& headers = m_response.headers(); + auto it_ce = headers.find(web::http::header_names::content_encoding); + if (it_ce != headers.end()) + { + auto alg = web::http::details::compression::stream_decompressor::to_compression_algorithm(it_ce->second); + + if (alg != web::http::details::compression::compression_algorithm::invalid) + { + m_decompressor = std::make_unique(alg); + } + else + { + report_exception( + http_exception("Unsupported compression algorithm in the Content-Encoding header: " + + utility::conversions::to_utf8string(it_ce->second))); + return false; + } + } + } + return true; +} + +void request_context::add_accept_encoding_header(utility::string_t& headers) const +{ + // Add the header needed to request a compressed response if supported on this platform and it has been specified in the config + if (web::http::details::compression::stream_decompressor::is_supported() && m_http_client->client_config().request_compressed_response()) + { + headers.append(U("Accept-Encoding: ")); + headers.append(web::http::details::compression::stream_decompressor::known_algorithms()); + headers.append(U("\r\n")); + } +} + concurrency::streams::streambuf request_context::_get_readbuffer() { auto instream = m_request.body(); diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 4ba3e0851b..600bf26605 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -718,11 +718,7 @@ class asio_context : public request_context, public std::enable_shared_from_this extra_headers.append(ctx->generate_basic_auth_header()); } - // Add the header needed to request a compressed response if supported on this platform and it has been specified in the config - if (web::http::details::compression::stream_decompressor::is_supported() && ctx->m_http_client->client_config().request_compressed_response()) - { - extra_headers.append("Accept-Encoding: deflate, gzip\r\n"); - } + ctx->add_accept_encoding_header(extra_headers); // Check user specified transfer-encoding. std::string transferencoding; @@ -1240,26 +1236,18 @@ class asio_context : public request_context, public std::enable_shared_from_this m_response.headers().add(utility::conversions::to_string_t(std::move(name)), utility::conversions::to_string_t(std::move(value))); } } - complete_headers(); m_content_length = std::numeric_limits::max(); // Without Content-Length header, size should be same as TCP stream - set it size_t max. m_response.headers().match(header_names::content_length, m_content_length); - utility::string_t content_encoding; - if(web::http::details::compression::stream_decompressor::is_supported() && m_response.headers().match(header_names::content_encoding, content_encoding)) + if (!this->handle_content_encoding_compression()) { - auto alg = web::http::details::compression::stream_decompressor::to_compression_algorithm(content_encoding); - - if (alg != web::http::details::compression::compression_algorithm::invalid) - { - m_decompressor = utility::details::make_unique(alg); - } - else - { - report_exception(std::runtime_error("Unsupported compression algorithm in the Content Encoding header: " + utility::conversions::to_utf8string(content_encoding))); - } + // false indicates report_exception was called + return; } + complete_headers(); + // Check for HEAD requests and status codes which cannot contain a // message body in HTTP/1.1 (see 3.3.3/1 of the RFC 7230). // @@ -1661,8 +1649,6 @@ class asio_context : public request_context, public std::enable_shared_from_this boost::asio::streambuf m_body_buf; std::shared_ptr m_connection; - std::unique_ptr m_decompressor; - #if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) bool m_openssl_failed; #endif diff --git a/Release/src/http/client/http_client_impl.h b/Release/src/http/client/http_client_impl.h index b292323ee0..4e47687aa4 100644 --- a/Release/src/http/client/http_client_impl.h +++ b/Release/src/http/client/http_client_impl.h @@ -70,6 +70,13 @@ class request_context report_exception(std::make_exception_ptr(e)); } + /// Set m_decompressor based on the response headers, or call report_exception + /// false on failure + bool handle_content_encoding_compression(); + + /// Append an Accept-Encoding header if requested by the http_client settings + void add_accept_encoding_header(utility::string_t& headers) const; + concurrency::streams::streambuf _get_writebuffer(); // Reference to the http_client implementation. @@ -88,6 +95,8 @@ class request_context // Registration for cancellation notification if enabled. pplx::cancellation_token_registration m_cancellationRegistration; + std::unique_ptr m_decompressor; + protected: request_context(const std::shared_ptr<_http_client_communicator> &client, const http_request &request); diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 2417859956..8f9b2b3146 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -245,7 +245,6 @@ class winhttp_request_context : public request_context // This self reference will keep us alive until finish() is called. std::shared_ptr m_self_reference; memory_holder m_body_data; - std::unique_ptr decompressor; virtual void cleanup() { @@ -733,15 +732,13 @@ class winhttp_client : public _http_client_communicator } } - if(web::http::details::compression::stream_decompressor::is_supported() && client_config().request_compressed_response()) - { - msg.headers().add(web::http::header_names::accept_encoding, U("deflate, gzip")); - } + utility::string_t flattened_headers = web::http::details::flatten_http_headers(msg.headers()); + + winhttp_context->add_accept_encoding_header(flattened_headers); // Add headers. - if(!msg.headers().empty()) + if(!flattened_headers.empty()) { - const utility::string_t flattened_headers = web::http::details::flatten_http_headers(msg.headers()); if(!WinHttpAddRequestHeaders( winhttp_context->m_request_handle, flattened_headers.c_str(), @@ -1371,22 +1368,10 @@ class winhttp_client : public _http_client_communicator } } - // If the response body is compressed we will read the encoding header and create a decompressor object which will later decompress the body - utility::string_t encoding; - if (web::http::details::compression::stream_decompressor::is_supported() && response.headers().match(web::http::header_names::content_encoding, encoding)) + if (!p_request_context->handle_content_encoding_compression()) { - auto alg = web::http::details::compression::stream_decompressor::to_compression_algorithm(encoding); - - if (alg != web::http::details::compression::compression_algorithm::invalid) - { - p_request_context->decompressor = std::make_unique(alg); - } - else - { - utility::string_t error = U("Unsupported compression algorithm in the Content Encoding header: "); - error += encoding; - p_request_context->report_exception(http_exception(error)); - } + // false indicates report_exception was called + return; } // Signal that the headers are available. @@ -1417,7 +1402,7 @@ class winhttp_client : public _http_client_communicator if(num_bytes > 0) { - if (p_request_context->decompressor) + if (p_request_context->m_decompressor) { // Decompression is too slow to reliably do on this callback. Therefore we need to store it now in order to decompress it at a later stage in the flow. // However, we want to eventually use the writebuf to store the decompressed body. Therefore we'll store the compressed body as an internal allocation in the request_context @@ -1486,11 +1471,11 @@ class winhttp_client : public _http_client_communicator auto writebuf = p_request_context->_get_writebuffer(); // If we have compressed data it is stored in the local allocation of the p_request_context. We will store the decompressed buffer in the external allocation of the p_request_context. - if (p_request_context->decompressor) + if (p_request_context->m_decompressor) { - web::http::details::compression::data_buffer decompressed = p_request_context->decompressor->decompress(p_request_context->m_body_data.get(), bytesRead); + web::http::details::compression::data_buffer decompressed = p_request_context->m_decompressor->decompress(p_request_context->m_body_data.get(), bytesRead); - if (p_request_context->decompressor->has_error()) + if (p_request_context->m_decompressor->has_error()) { p_request_context->report_exception(std::runtime_error("Failed to decompress the response body")); return; diff --git a/Release/tests/functional/http/client/request_helper_tests.cpp b/Release/tests/functional/http/client/request_helper_tests.cpp index cf7147ecb3..624dff19e2 100644 --- a/Release/tests/functional/http/client/request_helper_tests.cpp +++ b/Release/tests/functional/http/client/request_helper_tests.cpp @@ -30,6 +30,78 @@ namespace tests { namespace functional { namespace http { namespace client { SUITE(request_helper_tests) { +TEST_FIXTURE(uri_address, do_not_fail_on_content_encoding_when_not_requested) +{ + test_http_server::scoped_server scoped(m_uri); + auto& server = *scoped.server(); + http_client client(m_uri); + + server.next_request().then([](test_request *p_request) { + p_request->reply(200, U("OK"), { {header_names::content_encoding, U("chunked")} }); + }); + + http_asserts::assert_response_equals(client.request(methods::GET).get(), status_codes::OK); +} + +TEST_FIXTURE(uri_address, fail_on_content_encoding_if_unsupported) +{ + if (web::http::details::compression::stream_compressor::is_supported()) + { + test_http_server::scoped_server scoped(m_uri); + auto& server = *scoped.server(); + http_client_config config; + config.set_request_compressed_response(true); + http_client client(m_uri, config); + + server.next_request().then([](test_request *p_request) { + p_request->reply(200, U("OK"), { {header_names::content_encoding, U("unsupported-algorithm")} }); + }); + + VERIFY_THROWS(client.request(methods::GET).get(), web::http::http_exception); + } +} + +TEST_FIXTURE(uri_address, send_accept_encoding) +{ + if (web::http::details::compression::stream_compressor::is_supported()) + { + test_http_server::scoped_server scoped(m_uri); + auto& server = *scoped.server(); + http_client_config config; + config.set_request_compressed_response(true); + http_client client(m_uri, config); + + std::atomic found_accept_encoding = false; + + server.next_request().then([&found_accept_encoding](test_request *p_request) { + found_accept_encoding = p_request->m_headers.find(header_names::accept_encoding) != p_request->m_headers.end(); + p_request->reply(200, U("OK")); + }); + + client.request(methods::GET).get(); + + VERIFY_IS_TRUE(found_accept_encoding); + } +} + +TEST_FIXTURE(uri_address, do_not_send_accept_encoding) +{ + test_http_server::scoped_server scoped(m_uri); + auto& server = *scoped.server(); + http_client client(m_uri); + + std::atomic found_accept_encoding = true; + + server.next_request().then([&found_accept_encoding](test_request *p_request) { + found_accept_encoding = p_request->m_headers.find(header_names::accept_encoding) != p_request->m_headers.end(); + p_request->reply(200, U("OK")); + }); + + client.request(methods::GET).get(); + + VERIFY_IS_FALSE(found_accept_encoding); +} + TEST_FIXTURE(uri_address, compress_and_decompress) { if (web::http::details::compression::stream_compressor::is_supported()) From aa4065bd24aff94d790b31c4e11115359d8666bf Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Wed, 1 Aug 2018 02:01:01 -0700 Subject: [PATCH 216/438] Delete open() from _http_client_communicator (#819) * Delete open() from _http_client_communicator and move its functionality into WinHTTP, as that is the only backend using that thing. * Some CR comments from Robert. --- Release/src/http/client/http_client.cpp | 67 +++++-------------- Release/src/http/client/http_client_asio.cpp | 2 - Release/src/http/client/http_client_impl.h | 15 ++--- .../src/http/client/http_client_winhttp.cpp | 31 ++++++++- Release/src/http/client/http_client_winrt.cpp | 6 -- 5 files changed, 50 insertions(+), 71 deletions(-) diff --git a/Release/src/http/client/http_client.cpp b/Release/src/http/client/http_client.cpp index fdaca8f151..1e4e5036c2 100644 --- a/Release/src/http/client/http_client.cpp +++ b/Release/src/http/client/http_client.cpp @@ -167,7 +167,7 @@ request_context::request_context(const std::shared_ptr<_http_client_communicator responseImpl->_prepare_to_receive_data(); } -void _http_client_communicator::open_and_send_request_async(const std::shared_ptr &request) +void _http_client_communicator::async_send_request_impl(const std::shared_ptr &request) { auto self = std::static_pointer_cast<_http_client_communicator>(this->shared_from_this()); // Schedule a task to start sending. @@ -175,7 +175,7 @@ void _http_client_communicator::open_and_send_request_async(const std::shared_pt { try { - self->open_and_send_request(request); + self->send_request(request); } catch (...) { @@ -188,20 +188,21 @@ void _http_client_communicator::async_send_request(const std::shared_ptr &request) -{ - // First see if client needs to be opened. - unsigned long error = 0; - - if (!m_opened) - { - pplx::extensibility::scoped_critical_section_t l(m_open_lock); - - // Check again with the lock held - if (!m_opened) - { - error = open(); - - if (error == 0) - { - m_opened = true; - } - } - } - - if (error != 0) - { - // Failed to open - request->report_error(error, _XPLATSTR("Open failed")); - - // DO NOT TOUCH the this pointer after completing the request - // This object could be freed along with the request as it could - // be the last reference to this object - return; - } - - send_request(request); -} - inline void request_context::finish() { // If cancellation is enabled and registration was performed, unregister. @@ -437,4 +404,4 @@ pplx::task http_client::request(http_request request, const pplx: } -}}} \ No newline at end of file +}}} diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 600bf26605..f9b9ac1f73 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -400,8 +400,6 @@ class asio_client final : public _http_client_communicator void send_request(const std::shared_ptr &request_ctx) override; - unsigned long open() override { return 0; } - void release_connection(std::shared_ptr& conn) { m_pool->release(conn); diff --git a/Release/src/http/client/http_client_impl.h b/Release/src/http/client/http_client_impl.h index 4e47687aa4..e4508ebcf1 100644 --- a/Release/src/http/client/http_client_impl.h +++ b/Release/src/http/client/http_client_impl.h @@ -126,30 +126,23 @@ class _http_client_communicator : public http_pipeline_stage protected: _http_client_communicator(http::uri&& address, http_client_config&& client_config); - // Method to open client. - virtual unsigned long open() = 0; - // HTTP client implementations must implement send_request. virtual void send_request(_In_ const std::shared_ptr &request) = 0; // URI to connect to. const http::uri m_uri; + pplx::extensibility::critical_section_t m_client_lock; private: http_client_config m_client_config; - std::atomic m_opened; - - pplx::extensibility::critical_section_t m_open_lock; - // Wraps opening the client around sending a request. - void open_and_send_request_async(const std::shared_ptr &request); - void open_and_send_request(const std::shared_ptr &request); + void async_send_request_impl(const std::shared_ptr &request); // Queue used to guarantee ordering of requests, when applicable. std::queue> m_requests_queue; - int m_scheduled; + bool m_outstanding; }; /// @@ -157,4 +150,4 @@ class _http_client_communicator : public http_pipeline_stage /// std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage(uri&& base_uri, http_client_config&& client_config); -}}}} \ No newline at end of file +}}}} diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 8f9b2b3146..c81dd6b317 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -14,6 +14,8 @@ ****/ #include "stdafx.h" +#include + #include "cpprest/http_headers.h" #include "http_client_impl.h" @@ -350,6 +352,7 @@ class winhttp_client : public _http_client_communicator winhttp_client(http::uri address, http_client_config client_config) : _http_client_communicator(std::move(address), std::move(client_config)) , m_secure(m_uri.scheme() == _XPLATSTR("https")) + , m_opened(false) , m_hSession(nullptr) , m_hConnection(nullptr) { } @@ -402,8 +405,19 @@ class winhttp_client : public _http_client_communicator } // Open session and connection with the server. - virtual unsigned long open() override + unsigned long open() { + if (m_opened) + { + return 0; + } + + pplx::extensibility::scoped_critical_section_t l(m_client_lock); + if (m_opened) + { + return 0; + } + // This object have lifetime greater than proxy_name and proxy_bypass // which may point to its elements. ie_proxy_config proxyIE; @@ -574,12 +588,24 @@ class winhttp_client : public _http_client_communicator return report_failure(_XPLATSTR("Error opening connection")); } + m_opened = true; return S_OK; } // Start sending request. void send_request(_In_ const std::shared_ptr &request) { + // First see if we need to be opened. + unsigned long error = open(); + if (error != 0) + { + // DO NOT TOUCH the this pointer after completing the request + // This object could be freed along with the request as it could + // be the last reference to this object + request->report_error(error, _XPLATSTR("Open failed")); + return; + } + http_request &msg = request->m_request; std::shared_ptr winhttp_context = std::static_pointer_cast(request); std::weak_ptr weak_winhttp_context = winhttp_context; @@ -1531,6 +1557,8 @@ class winhttp_client : public _http_client_communicator } } + std::atomic m_opened; + // WinHTTP session and connection HINTERNET m_hSession; HINTERNET m_hConnection; @@ -1549,4 +1577,3 @@ std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage( } }}}} - diff --git a/Release/src/http/client/http_client_winrt.cpp b/Release/src/http/client/http_client_winrt.cpp index 4ada65a75b..e8ee50a018 100644 --- a/Release/src/http/client/http_client_winrt.cpp +++ b/Release/src/http/client/http_client_winrt.cpp @@ -378,12 +378,6 @@ class winrt_client : public _http_client_communicator protected: - // Method to open client. - unsigned long open() - { - return 0; - } - // Start sending request. void send_request(_In_ const std::shared_ptr &request) { From ef7e37e289c16dc82988d3675c9b40e4590cf1bc Mon Sep 17 00:00:00 2001 From: Gianfranco Costamagna Date: Wed, 1 Aug 2018 11:04:41 +0200 Subject: [PATCH 217/438] Fix boost1.63 build failure Fixes: #813 (#815) --- .../websocketpp/websocketpp/transport/asio/security/tls.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp b/Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp index 8932655803..74e4234766 100644 --- a/Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp +++ b/Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp @@ -312,7 +312,7 @@ class connection : public lib::enable_shared_from_this { return make_error_code(transport::error::tls_short_read); #else if (ERR_GET_REASON(ec.value()) == boost::asio::ssl::error::stream_truncated) { - return make_error_code(boost::asio::ssl::error::stream_truncated); + return make_error_code(static_cast(boost::asio::ssl::error::stream_truncated)); #endif } else { // We know it is a TLS related error, but otherwise don't know From fac1470f8ac757ff57c41b5b7ba75cf7027adcd2 Mon Sep 17 00:00:00 2001 From: Andreas Stieger Date: Wed, 1 Aug 2018 11:08:42 +0200 Subject: [PATCH 218/438] Fix gcc8 error/warning -Werror=format-truncation= (#787) utilities::datetime::to_string(): datetime_str and buf were oversized for fitting into output without possible trunctation --- Release/src/utilities/asyncrt_utils.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index 0e62bdeea4..be38907c6e 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -691,12 +691,13 @@ utility::string_t datetime::to_string(date_format format) const { // Append fractional second, which is a 7-digit value with no trailing zeros // This way, '1200' becomes '00012' - char buf[9] = { 0 }; + const int max_frac_length = 8; + char buf[max_frac_length+1] = { 0 }; snprintf(buf, sizeof(buf), ".%07ld", (long int)frac_sec); // trim trailing zeros - for (int i = 7; buf[i] == '0'; i--) buf[i] = '\0'; + for (int i = max_frac_length-1; buf[i] == '0'; i--) buf[i] = '\0'; // format the datetime into a separate buffer - char datetime_str[max_dt_length+1] = {0}; + char datetime_str[max_dt_length-max_frac_length-1+1] = {0}; strftime(datetime_str, sizeof(datetime_str), "%Y-%m-%dT%H:%M:%S", &datetime); // now print this buffer into the output buffer snprintf(output, sizeof(output), "%s%sZ", datetime_str, buf); From 48ae6d2fa09bc3f1c41e07638ead68c73a28595a Mon Sep 17 00:00:00 2001 From: Alex Moriarty Date: Wed, 1 Aug 2018 02:09:03 -0700 Subject: [PATCH 219/438] [gcc-8][clang++-6] disable more -Werror warnings (#779) gcc-8: -Wno-format-truncation clang-6: -Wdelete-non-virtual-dtor clang-6: -Wunused-lambda-capture removed duplicated: -Wno-reorder This fixes #778 --- Release/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 5362d1cd9e..aea81d7c0d 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -166,12 +166,12 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR IOS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-attributes -Wno-pointer-arith") elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") set(WARNINGS -Wall -Wextra -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls) - set(LINUX_SUPPRESSIONS -Wno-overloaded-virtual -Wno-sign-conversion -Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-char-subscripts -Wno-switch -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated -Wno-unused-value -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-unused-function -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-reorder -Wno-unused-local-typedefs) + set(LINUX_SUPPRESSIONS -Wno-overloaded-virtual -Wno-sign-conversion -Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-char-subscripts -Wno-switch -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated -Wno-unused-value -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-unused-function -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-unused-local-typedefs -Wno-delete-non-virtual-dtor -Wno-unused-lambda-capture) set(WARNINGS ${WARNINGS} ${LINUX_SUPPRESSIONS}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-return-type-c-linkage -Wno-unneeded-internal-declaration") else() set(WARNINGS -Wall -Wextra -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls) - set(OSX_SUPPRESSIONS -Wno-overloaded-virtual -Wno-sign-conversion -Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-char-subscripts -Wno-switch -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated -Wno-unused-value -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-unused-function -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-reorder -Wno-unused-local-typedefs) + set(OSX_SUPPRESSIONS -Wno-overloaded-virtual -Wno-sign-conversion -Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-char-subscripts -Wno-switch -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated -Wno-unused-value -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-unused-function -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-unused-local-typedefs -Wno-delete-non-virtual-dtor -Wno-unused-lambda-capture) set(WARNINGS ${WARNINGS} ${OSX_SUPPRESSIONS}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -Wno-return-type-c-linkage -Wno-unneeded-internal-declaration") @@ -184,7 +184,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR IOS) elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") message("-- Setting gcc options") - set(WARNINGS -Wall -Wextra -Wunused-parameter -Wcast-align -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls -Wunreachable-code) + set(WARNINGS -Wall -Wextra -Wunused-parameter -Wcast-align -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls -Wunreachable-code -Wno-format-truncation) set(LD_FLAGS "${LD_FLAGS} -Wl,-z,defs") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-strict-aliasing") From 08de668deb39ec868c92687cedf40e4f110b3ec8 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 1 Aug 2018 03:24:39 -0700 Subject: [PATCH 220/438] Fix some issues with gcc-5 --- Release/src/http/client/http_client.cpp | 2 +- Release/tests/functional/http/client/request_helper_tests.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Release/src/http/client/http_client.cpp b/Release/src/http/client/http_client.cpp index 1e4e5036c2..62701737cc 100644 --- a/Release/src/http/client/http_client.cpp +++ b/Release/src/http/client/http_client.cpp @@ -109,7 +109,7 @@ bool request_context::handle_content_encoding_compression() if (alg != web::http::details::compression::compression_algorithm::invalid) { - m_decompressor = std::make_unique(alg); + m_decompressor = utility::details::make_unique(alg); } else { diff --git a/Release/tests/functional/http/client/request_helper_tests.cpp b/Release/tests/functional/http/client/request_helper_tests.cpp index 624dff19e2..32a49490ef 100644 --- a/Release/tests/functional/http/client/request_helper_tests.cpp +++ b/Release/tests/functional/http/client/request_helper_tests.cpp @@ -71,7 +71,7 @@ TEST_FIXTURE(uri_address, send_accept_encoding) config.set_request_compressed_response(true); http_client client(m_uri, config); - std::atomic found_accept_encoding = false; + std::atomic found_accept_encoding(false); server.next_request().then([&found_accept_encoding](test_request *p_request) { found_accept_encoding = p_request->m_headers.find(header_names::accept_encoding) != p_request->m_headers.end(); @@ -90,7 +90,7 @@ TEST_FIXTURE(uri_address, do_not_send_accept_encoding) auto& server = *scoped.server(); http_client client(m_uri); - std::atomic found_accept_encoding = true; + std::atomic found_accept_encoding(true); server.next_request().then([&found_accept_encoding](test_request *p_request) { found_accept_encoding = p_request->m_headers.find(header_names::accept_encoding) != p_request->m_headers.end(); From 651bba7d2e99b083641eb9f57f3c9d9c6650284e Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 1 Aug 2018 03:25:05 -0700 Subject: [PATCH 221/438] Remove empty objects when using CMake on Windows --- Release/src/CMakeLists.txt | 21 ++++++++++++--------- Release/src/pplx/pplx.cpp | 2 +- Release/src/pplx/pplxwin.cpp | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index a37a8cff9d..86a2f45b3e 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -18,7 +18,6 @@ set(SOURCES http/client/http_client.cpp http/client/http_client_msg.cpp http/client/http_client_impl.h - http/client/x509_cert_utilities.cpp http/common/internal_http_helpers.h http/common/http_helpers.cpp http/common/http_msg.cpp @@ -31,7 +30,6 @@ set(SOURCES json/json.cpp json/json_parsing.cpp json/json_serialization.cpp - pplx/pplx.cpp uri/uri.cpp uri/uri_builder.cpp utilities/asyncrt_utils.cpp @@ -84,23 +82,25 @@ if(CPPREST_PPLX_IMPL STREQUAL "apple") find_library(COREFOUNDATION CoreFoundation "/") find_library(SECURITY Security "/") target_link_libraries(cpprest PUBLIC ${COREFOUNDATION} ${SECURITY}) - target_sources(cpprest PRIVATE pplx/pplxapple.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) + target_sources(cpprest PRIVATE pplx/pplxapple.cpp pplx/pplx.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) if(CPPREST_INSTALL_HEADERS) install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) endif() elseif(CPPREST_PPLX_IMPL STREQUAL "linux") - target_sources(cpprest PRIVATE pplx/pplxlinux.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) + target_sources(cpprest PRIVATE pplx/pplxlinux.cpp pplx/pplx.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) if(CPPREST_INSTALL_HEADERS) install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) endif() elseif(CPPREST_PPLX_IMPL STREQUAL "win") - target_sources(cpprest PRIVATE pplx/pplxwin.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) - if(CPPREST_INSTALL_HEADERS) - install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) + if(CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") + target_sources(cpprest PRIVATE pplx/threadpool.cpp ../include/pplx/threadpool.h) + if(CPPREST_INSTALL_HEADERS) + install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) + endif() endif() elseif(CPPREST_PPLX_IMPL STREQUAL "winpplx") target_compile_definitions(cpprest PUBLIC -DCPPREST_FORCE_PPLX=1) - target_sources(cpprest PRIVATE pplx/pplxwin.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) + target_sources(cpprest PRIVATE pplx/pplxwin.cpp pplx/pplx.cpp pplx/threadpool.cpp ../include/pplx/threadpool.h) if(CPPREST_INSTALL_HEADERS) install(FILES ../include/pplx/threadpool.h DESTINATION include/pplx) endif() @@ -115,7 +115,7 @@ if(CPPREST_HTTP_CLIENT_IMPL STREQUAL "asio") cpprest_find_boost() cpprest_find_openssl() target_compile_definitions(cpprest PUBLIC -DCPPREST_FORCE_HTTP_CLIENT_ASIO) - target_sources(cpprest PRIVATE http/client/http_client_asio.cpp) + target_sources(cpprest PRIVATE http/client/http_client_asio.cpp http/client/x509_cert_utilities.cpp) target_link_libraries(cpprest PUBLIC cpprestsdk_boost_internal cpprestsdk_openssl_internal) elseif(CPPREST_HTTP_CLIENT_IMPL STREQUAL "winhttp") target_link_libraries(cpprest PRIVATE @@ -123,6 +123,9 @@ elseif(CPPREST_HTTP_CLIENT_IMPL STREQUAL "winhttp") Winhttp.lib ) target_sources(cpprest PRIVATE http/client/http_client_winhttp.cpp) + if(CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") + target_sources(cpprest PRIVATE http/client/x509_cert_utilities.cpp) + endif() elseif(CPPREST_HTTP_CLIENT_IMPL STREQUAL "winrt") target_sources(cpprest PRIVATE http/client/http_client_winrt.cpp) else() diff --git a/Release/src/pplx/pplx.cpp b/Release/src/pplx/pplx.cpp index 40c76fc3b6..99d00e9ea5 100644 --- a/Release/src/pplx/pplx.cpp +++ b/Release/src/pplx/pplx.cpp @@ -13,7 +13,7 @@ #include "stdafx.h" -#if !defined(_WIN32) || _MSC_VER < 1800 || CPPREST_FORCE_PPLX +#if !defined(_WIN32) || CPPREST_FORCE_PPLX #include "pplx/pplx.h" diff --git a/Release/src/pplx/pplxwin.cpp b/Release/src/pplx/pplxwin.cpp index d586e7d69c..e511c0ad5d 100644 --- a/Release/src/pplx/pplxwin.cpp +++ b/Release/src/pplx/pplxwin.cpp @@ -13,7 +13,7 @@ #include "stdafx.h" -#if !defined(_WIN32) || _MSC_VER < 1800 || CPPREST_FORCE_PPLX +#if !defined(_WIN32) || CPPREST_FORCE_PPLX #include "pplx/pplxwin.h" From 3d5cb468b3d474b1cd2443b778f8419932583474 Mon Sep 17 00:00:00 2001 From: Zeke Snider Date: Fri, 2 Feb 2018 16:50:39 -0800 Subject: [PATCH 222/438] Don't enable certificate revocation check if client config has validate certificates set to false --- Release/src/http/client/http_client_winhttp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index c81dd6b317..737c430b71 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -667,7 +667,7 @@ class winhttp_client : public _http_client_communicator } // Enable the certificate revocation check - if (m_secure) + if (m_secure && client_config().validate_certificates()) { DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; if (!WinHttpSetOption(winhttp_context->m_request_handle, WINHTTP_OPTION_ENABLE_FEATURE, &dwEnableSSLRevocOpt, sizeof(dwEnableSSLRevocOpt))) From 074590c8fc53b262b3c4e15f61c4559c43254595 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 1 Aug 2018 14:00:35 -0700 Subject: [PATCH 223/438] Add tests for set_validate_certificates(false). --- .../functional/http/client/outside_tests.cpp | 92 +++++++++++++++---- 1 file changed, 72 insertions(+), 20 deletions(-) diff --git a/Release/tests/functional/http/client/outside_tests.cpp b/Release/tests/functional/http/client/outside_tests.cpp index 4c16fb4db6..00404a290f 100644 --- a/Release/tests/functional/http/client/outside_tests.cpp +++ b/Release/tests/functional/http/client/outside_tests.cpp @@ -75,7 +75,7 @@ TEST_FIXTURE(uri_address, outside_wikipedia_compressed_http_response) auto s = response.extract_utf8string().get(); VERIFY_IS_FALSE(s.empty()); - + utility::string_t encoding; VERIFY_IS_TRUE(response.headers().match(web::http::header_names::content_encoding, encoding)); @@ -93,14 +93,14 @@ TEST_FIXTURE(uri_address, outside_google_dot_com) VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); } } - + TEST_FIXTURE(uri_address, multiple_https_requests) { handle_timeout([&] { // Use code.google.com instead of www.google.com, which redirects http_client client(U("https://code.google.com/")); - + http_response response; for(int i = 0; i < 5; ++i) { @@ -155,38 +155,90 @@ TEST_FIXTURE(uri_address, no_transfer_encoding_content_length) // https://www.ssllabs.com/ssltest/ // http://www.internetsociety.org/deploy360/resources/dane-test-sites/ // https://onlinessl.netlock.hu/# -TEST(server_selfsigned_cert) +static void test_failed_ssl_cert(const uri& base_uri) { - handle_timeout([] + handle_timeout([&base_uri] { - http_client client(U("https://self-signed.badssl.com/")); + http_client client(base_uri); auto requestTask = client.request(methods::GET); VERIFY_THROWS(requestTask.get(), http_exception); }); } -TEST(server_hostname_mismatch) +#if !defined(__cplusplus_winrt) +static void test_ignored_ssl_cert(const uri& base_uri) { - handle_timeout([] + handle_timeout([&base_uri] { - http_client client(U("https://wrong.host.badssl.com/")); - auto requestTask = client.request(methods::GET); - VERIFY_THROWS(requestTask.get(), http_exception); + http_client_config config; + config.set_validate_certificates(false); + http_client client(base_uri, config); + auto request = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::OK, request.status_code()); }); } +#endif // !defined(__cplusplus_winrt) + +TEST(server_selfsigned_cert) +{ + test_failed_ssl_cert(U("https://self-signed.badssl.com/")); +} + +#if !defined(__cplusplus_winrt) +TEST(server_selfsigned_cert_ignored) +{ + test_ignored_ssl_cert(U("https://self-signed.badssl.com/")); +} +#endif // !defined(__cplusplus_winrt) + +TEST(server_hostname_mismatch) +{ + test_failed_ssl_cert(U("https://wrong.host.badssl.com/")); +} + +#if !defined(__cplusplus_winrt) +TEST(server_hostname_mismatch_ignored) +{ + test_ignored_ssl_cert(U("https://wrong.host.badssl.com/")); +} +#endif // !defined(__cplusplus_winrt) TEST(server_cert_expired) { - handle_timeout([] - { - http_client_config config; - config.set_timeout(std::chrono::seconds(1)); - http_client client(U("https://expired.badssl.com/"), config); - auto requestTask = client.request(methods::GET); - VERIFY_THROWS(requestTask.get(), http_exception); - }); + test_failed_ssl_cert(U("https://expired.badssl.com/")); +} + +#if !defined(__cplusplus_winrt) +TEST(server_cert_expired_ignored) +{ + test_ignored_ssl_cert(U("https://expired.badssl.com/")); +} +#endif // !defined(__cplusplus_winrt) + +TEST(server_cert_revoked) +{ + test_failed_ssl_cert(U("https://revoked.badssl.com/")); +} + +#if !defined(__cplusplus_winrt) +TEST(server_cert_revoked_ignored) +{ + test_ignored_ssl_cert(U("https://revoked.badssl.com/")); +} +#endif // !defined(__cplusplus_winrt) + +TEST(server_cert_untrusted) +{ + test_failed_ssl_cert(U("https://untrusted-root.badssl.com/")); } +#if !defined(__cplusplus_winrt) +TEST(server_cert_untrusted_ignored) +{ + test_ignored_ssl_cert(U("https://untrusted-root.badssl.com/")); +} +#endif // !defined(__cplusplus_winrt) + #if !defined(__cplusplus_winrt) TEST(ignore_server_cert_invalid, "Ignore:Android", "229", @@ -204,7 +256,7 @@ TEST(ignore_server_cert_invalid, VERIFY_ARE_EQUAL(status_codes::OK, request.status_code()); }); } -#endif +#endif // !defined(__cplusplus_winrt) TEST_FIXTURE(uri_address, outside_ssl_json) { From ee2cde689a41f55657ae405f515cc0f5b6062da3 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Wed, 1 Aug 2018 14:05:34 -0700 Subject: [PATCH 224/438] Unbreak ASIO build on Windows. (#821) --- Release/src/http/client/http_client.cpp | 8 +- Release/src/http/client/http_client_asio.cpp | 84 +++++++++---------- Release/src/http/client/http_client_impl.h | 2 +- .../src/http/client/http_client_winhttp.cpp | 3 +- 4 files changed, 50 insertions(+), 47 deletions(-) diff --git a/Release/src/http/client/http_client.cpp b/Release/src/http/client/http_client.cpp index 62701737cc..2963fae3c2 100644 --- a/Release/src/http/client/http_client.cpp +++ b/Release/src/http/client/http_client.cpp @@ -123,15 +123,19 @@ bool request_context::handle_content_encoding_compression() return true; } -void request_context::add_accept_encoding_header(utility::string_t& headers) const +utility::string_t request_context::get_accept_encoding_header() const { + utility::string_t headers; // Add the header needed to request a compressed response if supported on this platform and it has been specified in the config - if (web::http::details::compression::stream_decompressor::is_supported() && m_http_client->client_config().request_compressed_response()) + if (web::http::details::compression::stream_decompressor::is_supported() + && m_http_client->client_config().request_compressed_response()) { headers.append(U("Accept-Encoding: ")); headers.append(web::http::details::compression::stream_decompressor::known_algorithms()); headers.append(U("\r\n")); } + + return headers; } concurrency::streams::streambuf request_context::_get_readbuffer() diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index f9b9ac1f73..3a79963a0c 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -460,14 +460,14 @@ class asio_context : public request_context, public std::enable_shared_from_this ctx->m_timer.set_ctx(std::weak_ptr(ctx)); return ctx; } - + class ssl_proxy_tunnel : public std::enable_shared_from_this { public: ssl_proxy_tunnel(std::shared_ptr context, std::function)> ssl_tunnel_established) : m_ssl_tunnel_established(ssl_tunnel_established), m_context(context) {} - + void start_proxy_connect() { auto proxy = m_context->m_http_client->client_config().proxy(); @@ -502,7 +502,7 @@ class asio_context : public request_context, public std::enable_shared_from_this client->m_resolver.async_resolve(query, boost::bind(&ssl_proxy_tunnel::handle_resolve, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::iterator)); } - private: + private: void handle_resolve(const boost::system::error_code& ec, tcp::resolver::iterator endpoints) { if (ec) @@ -553,7 +553,7 @@ class asio_context : public request_context, public std::enable_shared_from_this m_context->report_error("Failed to send connect request to proxy.", err, httpclient_errorcode_context::writebody); } } - + void handle_status_line(const boost::system::error_code& ec) { if (!ec) @@ -565,13 +565,13 @@ class asio_context : public request_context, public std::enable_shared_from_this response_stream >> http_version; status_code status_code; response_stream >> status_code; - + if (!response_stream || http_version.substr(0, 5) != "HTTP/") { m_context->report_error("Invalid HTTP status line during proxy connection", ec, httpclient_errorcode_context::readheader); return; } - + if (status_code != 200) { m_context->report_error("Expected a 200 response from proxy, received: " + to_string(status_code), ec, httpclient_errorcode_context::readheader); @@ -593,14 +593,14 @@ class asio_context : public request_context, public std::enable_shared_from_this // Failed to write to socket because connection was already closed while it was in the pool. // close() here ensures socket is closed in a robust way and prevents the connection from being put to the pool again. m_context->m_connection->close(); - + // Create a new context and copy the request object, completion event and // cancellation registration to maintain the old state. // This also obtains a new connection from pool. auto new_ctx = m_context->create_request_context(m_context->m_http_client, m_context->m_request); new_ctx->m_request_completion = m_context->m_request_completion; new_ctx->m_cancellationRegistration = m_context->m_cancellationRegistration; - + auto client = std::static_pointer_cast(m_context->m_http_client); // Resend the request using the new context. client->send_request(new_ctx); @@ -611,15 +611,15 @@ class asio_context : public request_context, public std::enable_shared_from_this } } } - + std::function)> m_ssl_tunnel_established; std::shared_ptr m_context; - + boost::asio::streambuf m_request; boost::asio::streambuf m_response; }; - - + + enum class http_proxy_type { none, @@ -634,11 +634,11 @@ class asio_context : public request_context, public std::enable_shared_from_this request_context::report_error(make_error_code(std::errc::operation_canceled).value(), "Request canceled by user."); return; } - + http_proxy_type proxy_type = http_proxy_type::none; std::string proxy_host; int proxy_port = -1; - + // There is no support for auto-detection of proxies on non-windows platforms, it must be specified explicitly from the client code. if (m_http_client->client_config().proxy().is_specified()) { @@ -648,7 +648,7 @@ class asio_context : public request_context, public std::enable_shared_from_this proxy_port = proxy_uri.port() == -1 ? 8080 : proxy_uri.port(); proxy_host = utility::conversions::to_utf8string(proxy_uri.host()); } - + auto start_http_request_flow = [proxy_type, proxy_host, proxy_port AND_CAPTURE_MEMBER_FUNCTION_POINTERS](std::shared_ptr ctx) { if (ctx->m_request._cancellation_token().is_canceled()) @@ -656,20 +656,20 @@ class asio_context : public request_context, public std::enable_shared_from_this ctx->request_context::report_error(make_error_code(std::errc::operation_canceled).value(), "Request canceled by user."); return; } - + const auto &base_uri = ctx->m_http_client->base_uri(); const auto full_uri = uri_builder(base_uri).append(ctx->m_request.relative_uri()).to_uri(); - + // For a normal http proxy, we need to specify the full request uri, otherwise just specify the resource auto encoded_resource = proxy_type == http_proxy_type::http ? full_uri.to_string() : full_uri.resource().to_string(); - + if (encoded_resource.empty()) { encoded_resource = U("/"); } - + const auto &method = ctx->m_request.method(); - + // stop injection of headers via method // resource should be ok, since it's been encoded // and host won't resolve @@ -678,20 +678,20 @@ class asio_context : public request_context, public std::enable_shared_from_this ctx->report_exception(http_exception("The method string is invalid.")); return; } - + std::ostream request_stream(&ctx->m_body_buf); request_stream.imbue(std::locale::classic()); const auto &host = utility::conversions::to_utf8string(base_uri.host()); - + request_stream << utility::conversions::to_utf8string(method) << " " << utility::conversions::to_utf8string(encoded_resource) << " " << "HTTP/1.1" << CRLF; - + int port = base_uri.port(); - + if (base_uri.is_port_default()) { port = (ctx->m_connection->is_ssl() ? 443 : 80); } - + // Add the Host header if user has not specified it explicitly if (!ctx->m_request.headers().has(header_names::host)) { @@ -701,10 +701,10 @@ class asio_context : public request_context, public std::enable_shared_from_this } request_stream << CRLF; } - + // Extra request headers are constructed here. std::string extra_headers; - + // Add header for basic proxy authentication if (proxy_type == http_proxy_type::http && ctx->m_http_client->client_config().proxy().credentials().is_set()) { @@ -716,7 +716,7 @@ class asio_context : public request_context, public std::enable_shared_from_this extra_headers.append(ctx->generate_basic_auth_header()); } - ctx->add_accept_encoding_header(extra_headers); + extra_headers += utility::conversions::to_utf8string(ctx->get_accept_encoding_header()); // Check user specified transfer-encoding. std::string transferencoding; @@ -740,25 +740,25 @@ class asio_context : public request_context, public std::enable_shared_from_this extra_headers.append("Content-Length: 0\r\n"); } } - + if (proxy_type == http_proxy_type::http) { extra_headers.append( "Cache-Control: no-store, no-cache\r\n" "Pragma: no-cache\r\n"); } - + request_stream << utility::conversions::to_utf8string(::web::http::details::flatten_http_headers(ctx->m_request.headers())); request_stream << extra_headers; // Enforce HTTP connection keep alive (even for the old HTTP/1.0 protocol). request_stream << "Connection: Keep-Alive" << CRLF << CRLF; - + // Start connection timeout timer. if (!ctx->m_timer.has_started()) { ctx->m_timer.start(); } - + if (ctx->m_connection->is_reused() || proxy_type == http_proxy_type::ssl_tunnel) { // If socket is a reused connection or we're connected via an ssl-tunneling proxy, try to write the request directly. In both cases we have already established a tcp connection. @@ -768,16 +768,16 @@ class asio_context : public request_context, public std::enable_shared_from_this { // If the connection is new (unresolved and unconnected socket), then start async // call to resolve first, leading eventually to request write. - + // For normal http proxies, we want to connect directly to the proxy server. It will relay our request. auto tcp_host = proxy_type == http_proxy_type::http ? proxy_host : host; auto tcp_port = proxy_type == http_proxy_type::http ? proxy_port : port; - + tcp::resolver::query query(tcp_host, to_string(tcp_port)); auto client = std::static_pointer_cast(ctx->m_http_client); client->m_resolver.async_resolve(query, boost::bind(&asio_context::handle_resolve, ctx, boost::asio::placeholders::error, boost::asio::placeholders::iterator)); } - + // Register for notification on cancellation to abort this request. if (ctx->m_request._cancellation_token() != pplx::cancellation_token::none()) { @@ -794,7 +794,7 @@ class asio_context : public request_context, public std::enable_shared_from_this }); } }; - + if (proxy_type == http_proxy_type::ssl_tunnel) { // The ssl_tunnel_proxy keeps the context alive and then calls back once the ssl tunnel is established via 'start_http_request_flow' @@ -1073,7 +1073,7 @@ class asio_context : public request_context, public std::enable_shared_from_this // Reuse error handling. return handle_write_body(ec); } - + m_timer.reset(); const auto &progress = m_request._get_impl()->_progress_handler(); if (progress) @@ -1154,7 +1154,7 @@ class asio_context : public request_context, public std::enable_shared_from_this response_stream >> http_version; status_code status_code; response_stream >> status_code; - + std::string status_message; std::getline(response_stream, status_message); @@ -1418,7 +1418,7 @@ class asio_context : public request_context, public std::enable_shared_from_this } this_request->m_body_buf.consume(to_read + CRLF.size()); // consume crlf this_request->m_connection->async_read_until(this_request->m_body_buf, CRLF, boost::bind(&asio_context::handle_chunk_header, this_request, boost::asio::placeholders::error)); - }); + }); } } } @@ -1471,7 +1471,7 @@ class asio_context : public request_context, public std::enable_shared_from_this if(m_decompressor) { auto decompressed = m_decompressor->decompress(boost::asio::buffer_cast(m_body_buf.data()), read_size); - + if (m_decompressor->has_error()) { this_request->report_exception(std::runtime_error("Failed to decompress the response body")); @@ -1646,7 +1646,7 @@ class asio_context : public request_context, public std::enable_shared_from_this timeout_timer m_timer; boost::asio::streambuf m_body_buf; std::shared_ptr m_connection; - + #if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) bool m_openssl_failed; #endif @@ -1668,7 +1668,7 @@ void asio_client::send_request(const std::shared_ptr &request_c { client_config().invoke_nativehandle_options(ctx->m_connection->m_ssl_stream.get()); } - else + else { client_config().invoke_nativehandle_options(&(ctx->m_connection->m_socket)); } diff --git a/Release/src/http/client/http_client_impl.h b/Release/src/http/client/http_client_impl.h index e4508ebcf1..7b6c974a0d 100644 --- a/Release/src/http/client/http_client_impl.h +++ b/Release/src/http/client/http_client_impl.h @@ -75,7 +75,7 @@ class request_context bool handle_content_encoding_compression(); /// Append an Accept-Encoding header if requested by the http_client settings - void add_accept_encoding_header(utility::string_t& headers) const; + utility::string_t get_accept_encoding_header() const; concurrency::streams::streambuf _get_writebuffer(); diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index c81dd6b317..f92f252bd9 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -759,8 +759,7 @@ class winhttp_client : public _http_client_communicator } utility::string_t flattened_headers = web::http::details::flatten_http_headers(msg.headers()); - - winhttp_context->add_accept_encoding_header(flattened_headers); + flattened_headers += winhttp_context->get_accept_encoding_header(); // Add headers. if(!flattened_headers.empty()) From c55ada9659c140104e3366e67024a39f4376ce7b Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Wed, 1 Aug 2018 16:39:58 -0700 Subject: [PATCH 225/438] Add branchless is_alnum borrowed from MSVC++'s std::regex' _Is_word; should be about 5x faster. (#823) The _Is_word change resulted in the following results in microbenchmarks; the previous is_alnum looks like branching_ranges. .\word_character_test.exe 08/01/18 16:33:03 Running .\word_character_test.exe Run on (12 X 2904 MHz CPU s) CPU Caches: L1 Data 32K (x6) L1 Instruction 32K (x6) L2 Unified 262K (x6) L3 Unified 12582K (x1) -------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------- strchr_search 19426572900 ns 19421875000 ns 1 branching_ranges 7582129000 ns 7578125000 ns 1 branching_search 6592977800 ns 6593750000 ns 1 table_index 1091321300 ns 1078125000 ns 1 --- Release/include/cpprest/asyncrt_utils.h | 43 ++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index 68aa738be0..6abcc9fc34 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -19,6 +19,7 @@ #include #include #include +#include #include "pplx/pplxtasks.h" #include "cpprest/details/basic_types.h" @@ -356,11 +357,45 @@ namespace details /// Our own implementation of alpha numeric instead of std::isalnum to avoid /// taking global lock for performance reasons. /// - inline bool __cdecl is_alnum(char ch) + inline bool __cdecl is_alnum(const unsigned char uch) noexcept + { // test if uch is an alnum character + // special casing char to avoid branches + static constexpr bool is_alnum_table[UCHAR_MAX + 1] = + { + /* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */ + /* 0X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 1X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 2X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 3X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0-9 */ + /* 4X */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A-Z */ + /* 5X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, + /* 6X */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a-z */ + /* 7X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 + /* non-ASCII values initialized to 0 */ + }; + return (is_alnum_table[uch]); + } + + /// + /// Our own implementation of alpha numeric instead of std::isalnum to avoid + /// taking global lock for performance reasons. + /// + inline bool __cdecl is_alnum(const char ch) noexcept + { + return (is_alnum(static_cast(ch))); + } + + /// + /// Our own implementation of alpha numeric instead of std::isalnum to avoid + /// taking global lock for performance reasons. + /// + template + inline bool __cdecl is_alnum(Elem ch) noexcept { - return (ch >= '0' && ch <= '9') - || (ch >= 'A' && ch <= 'Z') - || (ch >= 'a' && ch <= 'z'); + // assumes 'x' == L'x' for the ASCII range + typedef typename std::make_unsigned::type UElem; + const auto uch = static_cast(ch); + return (uch <= static_cast('z') && is_alnum(static_cast(uch))); } /// From a6b41536e0cbb28a3ce57e2cd53f983e3312c3e0 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Wed, 1 Aug 2018 17:14:08 -0700 Subject: [PATCH 226/438] Unify handling of tolower operations to avoid locale sensitivity. (#822) --- 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 6abcc9fc34..b5e61c9d14 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -29,7 +29,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 @@ -428,19 +427,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 @@ -642,41 +670,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 - From 6b1e9d47702814c129255b0e91e19dafb651801e Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 1 Aug 2018 11:25:17 -0700 Subject: [PATCH 227/438] Push version to 2.10.3 --- Build/version.props | 2 +- Release/CMakeLists.txt | 2 +- Release/include/cpprest/version.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Build/version.props b/Build/version.props index 81b45b0316..983ce9e3c5 100644 --- a/Build/version.props +++ b/Build/version.props @@ -4,7 +4,7 @@ cpprest 2 10 - 2 + 3 $(CppRestSDKVersionMajor)_$(CppRestSDKVersionMinor) $(CppRestSDKVersionMajor).$(CppRestSDKVersionMinor) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index aea81d7c0d..5a60107b75 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -11,7 +11,7 @@ endif() set(CPPREST_VERSION_MAJOR 2) set(CPPREST_VERSION_MINOR 10) -set(CPPREST_VERSION_REVISION 2) +set(CPPREST_VERSION_REVISION 3) enable_testing() diff --git a/Release/include/cpprest/version.h b/Release/include/cpprest/version.h index f3d9602e67..a4cf42cb5b 100644 --- a/Release/include/cpprest/version.h +++ b/Release/include/cpprest/version.h @@ -5,7 +5,7 @@ */ #define CPPREST_VERSION_REVISION 2 #define CPPREST_VERSION_MINOR 10 -#define CPPREST_VERSION_MAJOR 2 +#define CPPREST_VERSION_MAJOR 3 #define CPPREST_VERSION (CPPREST_VERSION_MAJOR*100000+CPPREST_VERSION_MINOR*100+CPPREST_VERSION_REVISION) From e388a2e523f4d0b6aee2bb923637d82d8b969556 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Thu, 2 Aug 2018 15:40:30 -0700 Subject: [PATCH 228/438] Update changelog --- changelog.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/changelog.md b/changelog.md index c3db452003..047ca874f3 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,12 @@ +cpprestsdk (2.10.3) +---------------------- +* Added a root `CMakeLists.txt` to improve support for VS2017 Open Folder. +* PR#809 improves support for `/permissive-` in MSVC +* Issue#804 fixed a regression due to compression support; we no longer fail on unknown Content-Encoding headers if we did not set Accepts-Encoding +* PR#813 fixes build failure with boost 1.63 +* PR#779 PR#787 suppress and fix some warnings with new versions of gcc and clang +-- cpprestsdk team THU, 2 Aug 2018 15:52:00 -0800 + cpprestsdk (2.10.0) ---------------------- * Removed VS2013 MSBuild files. Use CMake with the "Visual Studio 12 2013" generator. From 8edc9a474c6a77bc5ba9984f3704ac56861b6c08 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Thu, 2 Aug 2018 19:35:36 -0700 Subject: [PATCH 229/438] Deduplicate some code in HTTP headers. (#825) --- Release/include/cpprest/http_headers.h | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/Release/include/cpprest/http_headers.h b/Release/include/cpprest/http_headers.h index f5bee96535..2bc1975acd 100644 --- a/Release/include/cpprest/http_headers.h +++ b/Release/include/cpprest/http_headers.h @@ -145,13 +145,15 @@ class http_headers template void add(const key_type& name, const _t1& value) { - if (has(name)) + auto printedValue = utility::conversions::details::print_string(value); + auto& mapVal = m_headers[name]; + if (mapVal.empty()) { - m_headers[name].append(_XPLATSTR(", ")).append(utility::conversions::details::print_string(value)); + mapVal = std::move(printedValue); } else { - m_headers[name] = utility::conversions::details::print_string(value); + mapVal.append(_XPLATSTR(", ")).append(std::move(printedValue)); } } @@ -212,20 +214,12 @@ class http_headers bool match(const key_type &name, _t1 &value) const { auto iter = m_headers.find(name); - if (iter != m_headers.end()) - { - // Check to see if doesn't have a value. - if(iter->second.empty()) - { - bind_impl(iter->second, value); - return true; - } - return bind_impl(iter->second, value); - } - else + if (iter == m_headers.end()) { return false; } + + return bind_impl(iter->second, value) || iter->second.empty(); } /// @@ -311,6 +305,7 @@ class http_headers ref = utility::conversions::to_utf16string(text); return true; } + bool bind_impl(const key_type &text, std::string &ref) const { ref = utility::conversions::to_utf8string(text); From c214c811b9666f71be791a713f967c974ba886bf Mon Sep 17 00:00:00 2001 From: mobileben Date: Thu, 2 Aug 2018 19:46:23 -0700 Subject: [PATCH 230/438] =?UTF-8?q?#436=20Building=20iOS=20doesn=E2=80=99t?= =?UTF-8?q?=20seem=20to=20work=20(#776)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This moves iOS.cmake into the file so there is on need to add it. Also allows for boost to be static libs versus framework --- Build_iOS/CMakeLists.txt | 6 +- Build_iOS/fix_ios_cmake_compiler.patch | 18 -- Build_iOS/iOS.cmake | 225 +++++++++++++++++++ Release/CMakeLists.txt | 2 +- Release/cmake/cpprest_find_boost.cmake | 17 +- Release/src/http/client/http_client_asio.cpp | 2 +- 6 files changed, 244 insertions(+), 26 deletions(-) delete mode 100644 Build_iOS/fix_ios_cmake_compiler.patch create mode 100644 Build_iOS/iOS.cmake diff --git a/Build_iOS/CMakeLists.txt b/Build_iOS/CMakeLists.txt index 16782b7d83..1c1ea90152 100644 --- a/Build_iOS/CMakeLists.txt +++ b/Build_iOS/CMakeLists.txt @@ -3,7 +3,11 @@ cmake_minimum_required(VERSION 2.6) enable_testing() -set(TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/ios-cmake/toolchain/iOS.cmake") +if (CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET) + set (ENV{CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET} ${CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET}) +endif() + +set(TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/iOS.cmake") set(SIM_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/build.i386" CACHE INTERNAL "") set(SIM_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../Release" CACHE INTERNAL "") diff --git a/Build_iOS/fix_ios_cmake_compiler.patch b/Build_iOS/fix_ios_cmake_compiler.patch deleted file mode 100644 index 85eeec18c4..0000000000 --- a/Build_iOS/fix_ios_cmake_compiler.patch +++ /dev/null @@ -1,18 +0,0 @@ -diff --git a/toolchain/iOS.cmake b/toolchain/iOS.cmake -index 195e3fc..567a8d3 100644 ---- a/toolchain/iOS.cmake -+++ b/toolchain/iOS.cmake -@@ -45,10 +45,10 @@ if (CMAKE_UNAME) - string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}") - endif (CMAKE_UNAME) - --# Force the compilers to gcc for iOS -+# Force the compilers to clang for iOS - include (CMakeForceCompiler) --CMAKE_FORCE_C_COMPILER (/usr/bin/gcc Apple) --CMAKE_FORCE_CXX_COMPILER (/usr/bin/g++ Apple) -+CMAKE_FORCE_C_COMPILER (/usr/bin/clang Apple) -+CMAKE_FORCE_CXX_COMPILER (/usr/bin/clang++ Apple) - set(CMAKE_AR ar CACHE FILEPATH "" FORCE) - - # Skip the platform compiler checks for cross compiling diff --git a/Build_iOS/iOS.cmake b/Build_iOS/iOS.cmake new file mode 100644 index 0000000000..7001592b30 --- /dev/null +++ b/Build_iOS/iOS.cmake @@ -0,0 +1,225 @@ +# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake +# files which are included with CMake 2.8.4 +# It has been altered for iOS development + +# Options: +# +# IOS_PLATFORM = OS (default) or SIMULATOR or SIMULATOR64 +# This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders +# OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch. +# SIMULATOR - used to build for the Simulator platforms, which have an x86 arch. +# +# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder +# By default this location is automatcially chosen based on the IOS_PLATFORM value above. +# If set manually, it will override the default location and force the user of a particular Developer Platform +# +# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder +# By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value. +# In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path. +# If set manually, this will force the use of a specific SDK version + +# Macros: +# +# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE) +# A convenience macro for setting xcode specific properties on targets +# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1") +# +# find_host_package (PROGRAM ARGS) +# A macro used to find executable programs on the host system, not within the iOS environment. +# Thanks to the android-cmake project for providing the command + +# Standard settings +set (CMAKE_SYSTEM_NAME Darwin) +set (CMAKE_SYSTEM_VERSION 1) +set (UNIX True) +set (APPLE True) +set (IOS True) + +# Required as of cmake 2.8.10 +set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE) + +# Allow external setting of CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET. This is clumsy +# but it provides flexibility of not having to hardcode the deployment version in the file or have +# numerous copies of the file +if ($ENV{CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET $ENV{CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET}) +endif ($ENV{CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET}) + +# Determine the cmake host system version so we know where to find the iOS SDKs +find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin) +if (CMAKE_UNAME) + exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION) + string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}") +endif (CMAKE_UNAME) + +# Use clang. Use xcrun to determine the location +EXEC_PROGRAM(xcrun ARGS -find clang OUTPUT_VARIABLE APPLE_CLANG) +EXEC_PROGRAM(xcrun ARGS -find clang++ OUTPUT_VARIABLE APPLE_CLANGPP) +set (CMAKE_C_COMPILER ${APPLE_CLANG}) +set (CMAKE_CXX_COMPILER ${APPLE_CLANGPP}) + +set (CMAKE_AR ar CACHE FILEPATH "" FORCE) + +set (CMAKE_THREAD_LIBS_INIT "-lpthread") +set (CMAKE_HAVE_THREADS_LIBRARY 1) +set (CMAKE_USE_WIN32_THREADS_INIT 0) +set (CMAKE_USE_PTHREADS_INIT 1) + +# Skip the platform compiler checks for cross compiling +set (CMAKE_CXX_COMPILER_WORKS TRUE) +set (CMAKE_C_COMPILER_WORKS TRUE) + +# All iOS/Darwin specific settings - some may be redundant +set (CMAKE_SHARED_LIBRARY_PREFIX "lib") +set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib") +set (CMAKE_SHARED_MODULE_PREFIX "lib") +set (CMAKE_SHARED_MODULE_SUFFIX ".so") +set (CMAKE_MODULE_EXISTS 1) +set (CMAKE_DL_LIBS "") + +set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ") +set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ") +set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") +set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") + +# Hidden visibilty is required for cxx on iOS +set (CMAKE_C_FLAGS_INIT "") +set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden") + +set (CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "" CACHE STRING "Force unset of CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN" FORCE) + +set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}") +set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}") + +set (CMAKE_PLATFORM_HAS_INSTALLNAME 1) +set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names") +set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names") +set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,") +set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,") +set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a") +set (CMAKE_MACOSX_BUNDLE ON) +set (CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED OFF) + + +# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree +# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache +# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun) +# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex +if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) + find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool) +endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) + +# Setup iOS platform unless specified manually with IOS_PLATFORM +if (NOT DEFINED IOS_PLATFORM) + set (IOS_PLATFORM "OS") +endif (NOT DEFINED IOS_PLATFORM) +set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform") + +# Setup building for arm64 or not +if (NOT DEFINED BUILD_ARM64) + set (BUILD_ARM64 true) +endif (NOT DEFINED BUILD_ARM64) +set (BUILD_ARM64 ${BUILD_ARM64} CACHE STRING "Build arm64 arch or not") + +# Check the platform selection and setup for developer root +if (${IOS_PLATFORM} STREQUAL "OS") + set (IOS_PLATFORM_LOCATION "iPhoneOS.platform") + + # This causes the installers to properly locate the output libraries + set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos") +elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR") + set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform") + + # This causes the installers to properly locate the output libraries + set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator") +elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR64") + set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform") + + # This causes the installers to properly locate the output libraries + set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator") +else (${IOS_PLATFORM} STREQUAL "OS") + message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR") +endif (${IOS_PLATFORM} STREQUAL "OS") + +# Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT +# Note Xcode 4.3 changed the installation location, choose the most recent one available +exec_program(/usr/bin/xcode-select ARGS -print-path OUTPUT_VARIABLE CMAKE_XCODE_DEVELOPER_DIR) +set (XCODE_POST_43_ROOT "${CMAKE_XCODE_DEVELOPER_DIR}/Platforms/${IOS_PLATFORM_LOCATION}/Developer") +set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") +if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) + if (EXISTS ${XCODE_POST_43_ROOT}) + set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT}) + elseif(EXISTS ${XCODE_PRE_43_ROOT}) + set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT}) + endif (EXISTS ${XCODE_POST_43_ROOT}) +endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) +set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform") + +# Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT +if (NOT DEFINED CMAKE_IOS_SDK_ROOT) + file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*") + if (_CMAKE_IOS_SDKS) + list (SORT _CMAKE_IOS_SDKS) + list (REVERSE _CMAKE_IOS_SDKS) + list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT) + else (_CMAKE_IOS_SDKS) + message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.") + endif (_CMAKE_IOS_SDKS) + message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}") +endif (NOT DEFINED CMAKE_IOS_SDK_ROOT) +set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK") + +# Set the sysroot default to the most recent SDK +set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support") + +# set the architecture for iOS +if (${IOS_PLATFORM} STREQUAL "OS") + set (IOS_ARCH armv7 armv7s arm64) +elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR") + set (IOS_ARCH i386) +elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR64") + set (IOS_ARCH x86_64) +endif (${IOS_PLATFORM} STREQUAL "OS") + +set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS") + +# Set the find root to the iOS developer roots and to user defined paths +set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string "iOS find search path root") + +# default to searching for frameworks first +set (CMAKE_FIND_FRAMEWORK FIRST) + +# set up the default search directories for frameworks +set (CMAKE_SYSTEM_FRAMEWORK_PATH + ${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks + ${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks + ${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks +) + +# only search the iOS sdks, not the remainder of the host filesystem +set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) +set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + + +# This little macro lets you set any XCode specific property +macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE) + set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE}) +endmacro (set_xcode_property) + + +# This macro lets you find executable programs on the host system +macro (find_host_package) + set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) + set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) + set (IOS FALSE) + + find_package(${ARGN}) + + set (IOS TRUE) + set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) + set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endmacro (find_host_package) + diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 5a60107b75..1c6f88f286 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -115,7 +115,7 @@ set(ANDROID_STL_FLAGS) # Platform (not compiler) specific settings if(IOS) # The cxx_flags must be reset here, because the ios-cmake toolchain file unfortunately sets "-headerpad_max_install_names" which is not a valid clang flag. - set(CMAKE_CXX_FLAGS "-fvisibility=hidden -fvisibility-inlines-hidden") + set(CMAKE_CXX_FLAGS "-fvisibility=hidden") elseif(ANDROID) if(ARM) set(LIBCXX_STL "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a/thumb/libgnustl_static.a") diff --git a/Release/cmake/cpprest_find_boost.cmake b/Release/cmake/cpprest_find_boost.cmake index 298b080aae..67f5dad9b8 100644 --- a/Release/cmake/cpprest_find_boost.cmake +++ b/Release/cmake/cpprest_find_boost.cmake @@ -4,9 +4,15 @@ function(cpprest_find_boost) endif() if(IOS) - set(IOS_SOURCE_DIR "${PROJECT_SOURCE_DIR}/../Build_iOS") - set(Boost_LIBRARIES "${IOS_SOURCE_DIR}/boost.framework/boost" CACHE INTERNAL "") - set(Boost_INCLUDE_DIR "${IOS_SOURCE_DIR}/boost.framework/Headers" CACHE INTERNAL "") + if (EXISTS "${PROJECT_SOURCE_DIR}/../Build_iOS/boost") + set(IOS_SOURCE_DIR "${PROJECT_SOURCE_DIR}/../Build_iOS") + set(Boost_LIBRARIES "${IOS_SOURCE_DIR}/boost/lib" CACHE INTERNAL "") + set(Boost_INCLUDE_DIR "${IOS_SOURCE_DIR}/boost/include" CACHE INTERNAL "") + else() + set(IOS_SOURCE_DIR "${PROJECT_SOURCE_DIR}/../Build_iOS") + set(Boost_LIBRARIES "${IOS_SOURCE_DIR}/boost.framework/boost" CACHE INTERNAL "") + set(Boost_INCLUDE_DIR "${IOS_SOURCE_DIR}/boost.framework/Headers" CACHE INTERNAL "") + endif() elseif(ANDROID) set(Boost_COMPILER "-clang") if(ARM) @@ -42,8 +48,9 @@ function(cpprest_find_boost) endif() set(_prev "${_lib}") endforeach() - target_link_libraries(cpprestsdk_boost_internal INTERFACE "$") - + if (NOT IOS OR NOT EXISTS "${PROJECT_SOURCE_DIR}/../Build_iOS/boost") + target_link_libraries(cpprestsdk_boost_internal INTERFACE "$") + endif() else() if(ANDROID) target_link_libraries(cpprestsdk_boost_internal INTERFACE diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 3a79963a0c..df25c32aaa 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -47,7 +47,7 @@ #include #include -#if defined(__GNUC__) +#if defined(__GNUC__) && !defined(__clang__) #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) #define AND_CAPTURE_MEMBER_FUNCTION_POINTERS From c8c92277dbc3639dba479d823b4719b28e404e90 Mon Sep 17 00:00:00 2001 From: "sridhar madhugiri (msft)" Date: Thu, 2 Aug 2018 22:24:23 -0700 Subject: [PATCH 231/438] Improve error handling in on_accept (#750) * Improve error handling in on_accept * Move lock to the top of the function * Lock shared data at the right locations. * [http_listener] improve refcount and lifetime management by using RAII. --- .../src/http/listener/http_server_asio.cpp | 98 ++++++++++++++----- 1 file changed, 75 insertions(+), 23 deletions(-) diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 78193fa3e2..bef47126dc 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -200,7 +200,7 @@ namespace } private: - void on_accept(boost::asio::ip::tcp::socket* socket, const boost::system::error_code& ec); + void on_accept(std::unique_ptr socket, const boost::system::error_code& ec); }; @@ -333,7 +333,6 @@ class asio_server_connection std::unique_ptr m_ssl_context; std::unique_ptr m_ssl_stream; -public: asio_server_connection(std::unique_ptr socket, http_linux_server* server, hostport_listener* parent) : m_socket(std::move(socket)) , m_request_buf() @@ -341,12 +340,34 @@ class asio_server_connection , m_p_server(server) , m_p_parent(parent) , m_close(false) + , m_chunked(false) , m_refs(1) { } - will_deref_and_erase_t start(bool is_https, const std::function& ssl_context_callback) + struct Dereferencer + { + void operator()(asio_server_connection* conn) const { conn->deref(); } + }; + +public: + using refcount_ptr = std::unique_ptr; + + static refcount_ptr create(std::unique_ptr socket, http_linux_server* server, hostport_listener* parent) + { + return refcount_ptr(new asio_server_connection(std::move(socket), server, parent)); + } + + refcount_ptr get_reference() { + ++m_refs; + return refcount_ptr(this); + } + + will_erase_from_parent_t start_connection(bool is_https, const std::function& ssl_context_callback) + { + auto unique_reference = this->get_reference(); + if (is_https) { m_ssl_context = make_unique(boost::asio::ssl::context::sslv23); @@ -360,11 +381,14 @@ class asio_server_connection { (will_deref_and_erase_t)this->start_request_response(); }); - return will_deref_and_erase_t{}; + unique_reference.release(); + return will_erase_from_parent_t{}; } else { - return start_request_response(); + (will_deref_and_erase_t)start_request_response(); + unique_reference.release(); + return will_erase_from_parent_t{}; } } @@ -385,7 +409,7 @@ class asio_server_connection will_deref_and_erase_t dispatch_request_to_listener(); will_erase_from_parent_t do_response() { - ++m_refs; + auto unique_reference = this->get_reference(); m_request.get_response().then([=](pplx::task r_task) { http_response response; @@ -406,11 +430,12 @@ class asio_server_connection (will_deref_and_erase_t)this->async_write(&asio_server_connection::handle_headers_written, response); }); }); + unique_reference.release(); return will_erase_from_parent_t{}; } will_erase_from_parent_t do_bad_response() { - ++m_refs; + auto unique_reference = this->get_reference(); m_request.get_response().then([=](pplx::task r_task) { http_response response; @@ -428,6 +453,7 @@ class asio_server_connection (will_deref_and_erase_t)async_write(&asio_server_connection::handle_headers_written, response); }); + unique_reference.release(); return will_erase_from_parent_t{}; } @@ -495,10 +521,13 @@ void hostport_listener::start() m_acceptor->listen(0 != m_backlog ? m_backlog : socket_base::max_connections); auto socket = new ip::tcp::socket(service); + std::unique_ptr usocket(socket); m_acceptor->async_accept(*socket, [this, socket](const boost::system::error_code& ec) { - this->on_accept(socket, ec); + std::unique_ptr usocket(socket); + this->on_accept(std::move(usocket), ec); }); + usocket.release(); } void asio_server_connection::close() @@ -538,30 +567,53 @@ will_deref_and_erase_t asio_server_connection::start_request_response() return will_deref_and_erase_t{}; } -void hostport_listener::on_accept(ip::tcp::socket* socket, const boost::system::error_code& ec) +void hostport_listener::on_accept(std::unique_ptr socket, const boost::system::error_code& ec) { - std::unique_ptr usocket(std::move(socket)); + // Listener closed + if (ec == boost::asio::error::operation_aborted) + { + return; + } + + std::lock_guard lock(m_connections_lock); + // Handle successful accept if (!ec) { - auto conn = new asio_server_connection(std::move(usocket), m_p_server, this); + auto conn = asio_server_connection::create(std::move(socket), m_p_server, this); - std::lock_guard lock(m_connections_lock); - m_connections.insert(conn); - conn->start(m_is_https, m_ssl_context_callback); - if (m_connections.size() == 1) - m_all_connections_complete.reset(); + m_connections.insert(conn.get()); + try + { + (will_erase_from_parent_t)conn->start_connection(m_is_https, m_ssl_context_callback); + // at this point an asynchronous task has been launched which will call + // m_connections.erase(conn.get()) eventually - if (m_acceptor) + // the following cannot throw + if (m_connections.size() == 1) + m_all_connections_complete.reset(); + } + catch (boost::system::system_error&) { - // spin off another async accept - auto newSocket = new ip::tcp::socket(crossplat::threadpool::shared_instance().service()); - m_acceptor->async_accept(*newSocket, [this, newSocket](const boost::system::error_code& ec) - { - this->on_accept(newSocket, ec); - }); + // boost ssl apis throw boost::system::system_error. + // Exception indicates something went wrong setting ssl context. + // Drop connection and continue handling other connections. + m_connections.erase(conn.get()); } } + + if (m_acceptor) + { + // spin off another async accept + auto newSocket = new ip::tcp::socket(crossplat::threadpool::shared_instance().service()); + std::unique_ptr usocket(newSocket); + m_acceptor->async_accept(*newSocket, [this, newSocket](const boost::system::error_code& ec) + { + std::unique_ptr usocket(newSocket); + this->on_accept(std::move(usocket), ec); + }); + usocket.release(); + } } will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::system::error_code& ec) From 5021303f339f10c946022401d46d5abdc7c8cb48 Mon Sep 17 00:00:00 2001 From: VZ Date: Fri, 3 Aug 2018 08:18:05 +0200 Subject: [PATCH 232/438] Fix handling of timed out connections kept alive in connection pool under Unix (#762) * Add asio_connection::was_closed_by_server() to reduce duplication Reduce code duplication between ssl_proxy_tunnel::handle_status_line() and the method with the same name in asio_context itself by moving the common handling of connections closed by server into a new function. No real changes, this is a pure refactoring. * Fix checking for server-side closure of HTTPS connections When an SSL connection times out due to being closed by server, a different error code is returned, so we need to check for it too in was_closed_by_server(). Without this, losing connection was not detected at all when using HTTPS, resulting in "Failed to read HTTP status line" errors whenever the same http_client was reused after more than the server keep alive timeout of inactivity. See #592. * Fix bug with using re-opened connections with ASIO Creating a new request when the existing connection being used was closed by the server didn't work correctly because the associated input stream was already exhausted, as its contents had been already "sent" to the server using the now discarded connection, so starting a new request using the same body stream never worked. Fix this by explicitly rewinding the stream to the beginning before using it again. Note that even with this fix using a custom body stream which is not positioned at the beginning initially (or which doesn't support rewinding) still wouldn't work, but at least it fixes the most common use case. See #592. * Reduce duplicate code between ssl_proxy and asio_context in handle_read_status_line. Avoid increasing public surface with rewind function. --- Release/src/http/client/http_client_asio.cpp | 126 +++++++++++-------- 1 file changed, 74 insertions(+), 52 deletions(-) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index df25c32aaa..3bf1fcba23 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -28,6 +28,7 @@ #endif #include #include +#include #include #include #include @@ -170,6 +171,45 @@ class asio_connection bool keep_alive() const { return m_keep_alive; } bool is_ssl() const { return m_ssl_stream ? true : false; } + // Check if the error code indicates that the connection was closed by the + // server: this is used to detect if a connection in the pool was closed during + // its period of inactivity and we should reopen it. + bool was_reused_and_closed_by_server(const boost::system::error_code& ec) const + { + if (!is_reused()) + { + // Don't bother reopening the connection if it's a new one: in this + // case, even if the connection was really lost, it's still a real + // error and we shouldn't try to reopen it. + return false; + } + + // These errors tell if connection was closed. + if ((boost::asio::error::eof == ec) + || (boost::asio::error::connection_reset == ec) + || (boost::asio::error::connection_aborted == ec)) + { + return true; + } + + if (is_ssl()) + { + // For SSL connections, we can also get a different error due to + // incorrect secure connection shutdown if it was closed by the + // server due to inactivity. Unfortunately, the exact error we get + // in this case depends on the Boost.Asio version used. +#if BOOST_ASIO_VERSION >= 101008 + if (boost::asio::ssl::error::stream_truncated == ec) + return true; +#else // Asio < 1.10.8 didn't have ssl::error::stream_truncated + if (boost::system::error_code(ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ), boost::asio::error::get_ssl_category()) == ec) + return true; +#endif + } + + return false; + } + template void async_connect(const Iterator &begin, const Handler &handler) { @@ -578,37 +618,13 @@ class asio_context : public request_context, public std::enable_shared_from_this return; } - m_context->m_connection->upgrade_to_ssl(m_context->m_http_client->client_config().get_ssl_context_callback()); + m_context->upgrade_to_ssl(); m_ssl_tunnel_established(m_context); } else { - // These errors tell if connection was closed. - const bool socket_was_closed((boost::asio::error::eof == ec) - || (boost::asio::error::connection_reset == ec) - || (boost::asio::error::connection_aborted == ec)); - if (socket_was_closed && m_context->m_connection->is_reused()) - { - // Failed to write to socket because connection was already closed while it was in the pool. - // close() here ensures socket is closed in a robust way and prevents the connection from being put to the pool again. - m_context->m_connection->close(); - - // Create a new context and copy the request object, completion event and - // cancellation registration to maintain the old state. - // This also obtains a new connection from pool. - auto new_ctx = m_context->create_request_context(m_context->m_http_client, m_context->m_request); - new_ctx->m_request_completion = m_context->m_request_completion; - new_ctx->m_cancellationRegistration = m_context->m_cancellationRegistration; - - auto client = std::static_pointer_cast(m_context->m_http_client); - // Resend the request using the new context. - client->send_request(new_ctx); - } - else - { - m_context->report_error("Failed to read HTTP status line from proxy", ec, httpclient_errorcode_context::readheader); - } + m_context->handle_failed_read_status_line(ec, "Failed to read HTTP status line from proxy"); } } @@ -619,7 +635,6 @@ class asio_context : public request_context, public std::enable_shared_from_this boost::asio::streambuf m_response; }; - enum class http_proxy_type { none, @@ -821,6 +836,11 @@ class asio_context : public request_context, public std::enable_shared_from_this } private: + void upgrade_to_ssl() + { + m_connection->upgrade_to_ssl(m_http_client->client_config().get_ssl_context_callback()); + } + std::string generate_basic_auth_header() { std::string header; @@ -1173,31 +1193,33 @@ class asio_context : public request_context, public std::enable_shared_from_this } else { - // These errors tell if connection was closed. - const bool socket_was_closed((boost::asio::error::eof == ec) - || (boost::asio::error::connection_reset == ec) - || (boost::asio::error::connection_aborted == ec)); - if (socket_was_closed && m_connection->is_reused()) - { - // Failed to write to socket because connection was already closed while it was in the pool. - // close() here ensures socket is closed in a robust way and prevents the connection from being put to the pool again. - m_connection->close(); - - // Create a new context and copy the request object, completion event and - // cancellation registration to maintain the old state. - // This also obtains a new connection from pool. - auto new_ctx = create_request_context(m_http_client, m_request); - new_ctx->m_request_completion = m_request_completion; - new_ctx->m_cancellationRegistration = m_cancellationRegistration; - - auto client = std::static_pointer_cast(m_http_client); - // Resend the request using the new context. - client->send_request(new_ctx); - } - else - { - report_error("Failed to read HTTP status line", ec, httpclient_errorcode_context::readheader); - } + handle_failed_read_status_line(ec, "Failed to read HTTP status line"); + } + } + + void handle_failed_read_status_line(const boost::system::error_code& ec, const char* generic_error_message) + { + if (m_connection->was_reused_and_closed_by_server(ec)) + { + // Failed to write to socket because connection was already closed while it was in the pool. + // close() here ensures socket is closed in a robust way and prevents the connection from being put to the pool again. + m_connection->close(); + + // Create a new context and copy the request object, completion event and + // cancellation registration to maintain the old state. + // This also obtains a new connection from pool. + auto new_ctx = create_request_context(m_http_client, m_request); + new_ctx->m_request._get_impl()->instream().seek(0); + new_ctx->m_request_completion = m_request_completion; + new_ctx->m_cancellationRegistration = m_cancellationRegistration; + + auto client = std::static_pointer_cast(m_http_client); + // Resend the request using the new context. + client->send_request(new_ctx); + } + else + { + report_error(generic_error_message, ec, httpclient_errorcode_context::readheader); } } From ecabd2b0e0140b2c85cbaa376713f625be99f922 Mon Sep 17 00:00:00 2001 From: Gianfranco Costamagna Date: Fri, 3 Aug 2018 08:39:05 +0200 Subject: [PATCH 233/438] Update CMakeLists.txt to install the cmake bindings in the right location (#737) * Update CMakeLists.txt to install the cmake bindings in the right location /usr/lib/cpprestsdk is not the correct FHS standard cmake location. It should be placed in /usr/lib//cmake/cpprestsdk instead. Same goes for libraries, support multiarch location if we use UNIX * Revert changes to CPPREST_EXPORT_DIR. Use GNUInstallDirs on all platforms. --- Release/CMakeLists.txt | 1 + Release/src/CMakeLists.txt | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 1c6f88f286..a79a4ffbbc 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -63,6 +63,7 @@ include(cmake/cpprest_find_zlib.cmake) include(cmake/cpprest_find_openssl.cmake) include(cmake/cpprest_find_websocketpp.cmake) include(CheckIncludeFiles) +include(GNUInstallDirs) find_package(Threads REQUIRED) if(THREADS_HAVE_PTHREAD_ARG) diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index 86a2f45b3e..a34605bda2 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -253,9 +253,9 @@ if(CPPREST_INSTALL) install( TARGETS ${CPPREST_TARGETS} EXPORT cpprestsdk-targets - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) configure_file(../cmake/cpprestsdk-config.in.cmake "${CMAKE_CURRENT_BINARY_DIR}/cpprestsdk-config.cmake" @ONLY) From 14adc2e631fdf476969f2bdcb415d895400e7af1 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Thu, 2 Aug 2018 23:45:08 -0700 Subject: [PATCH 234/438] Various micro perf fixes and cleanup found while implementing CN overrides so far (#818) * Microperf: Use lock_guard instead of unique_lock. * Bill hates lock_guard more. * Ref them connections. * Demacroize. * Commonize port and merge some CRLFs into adjacent string literals. * Add missing template keyword. * Avoid stringstream in constructing the proxy_str. * Remove unused forward declarations of some HTTP things. * Use NOMINMAX instead of undef min and max everywhere. * Bunch of inheritance hygiene. * What do you mean you want examples to compile? * More CR comments from Robert. * Add static. * Use existing to_string_t. --- Release/include/cpprest/asyncrt_utils.h | 8 +-- .../include/cpprest/details/web_utilities.h | 11 ---- Release/include/cpprest/streams.h | 2 +- Release/src/http/client/http_client_asio.cpp | 50 +++++++++---------- .../src/http/client/http_client_winhttp.cpp | 23 +++------ Release/src/http/client/http_client_winrt.cpp | 15 +++--- Release/src/http/common/http_msg.cpp | 3 -- .../src/http/listener/http_server_asio.cpp | 7 +-- .../src/http/listener/http_server_httpsys.cpp | 15 +++--- Release/src/json/json.cpp | 4 -- Release/src/pch/stdafx.h | 3 +- .../src/websockets/client/ws_client_wspp.cpp | 15 +++--- 12 files changed, 60 insertions(+), 96 deletions(-) diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index b5e61c9d14..3fbebd7d95 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -228,7 +228,7 @@ namespace conversions #if defined(__ANDROID__) template - inline std::string to_string(const T& t) + inline std::string to_string(const T t) { std::ostringstream os; os.imbue(std::locale::classic()); @@ -238,16 +238,16 @@ namespace conversions #endif template - inline utility::string_t to_string_t(T&& t) + inline utility::string_t to_string_t(const T t) { #ifdef _UTF16_STRINGS using std::to_wstring; - return to_wstring(std::forward(t)); + return to_wstring(t); #else #if !defined(__ANDROID__) using std::to_string; #endif - return to_string(std::forward(t)); + return to_string(t); #endif } diff --git a/Release/include/cpprest/details/web_utilities.h b/Release/include/cpprest/details/web_utilities.h index ba6416546e..f99a8aa933 100644 --- a/Release/include/cpprest/details/web_utilities.h +++ b/Release/include/cpprest/details/web_utilities.h @@ -14,17 +14,6 @@ namespace web { - -namespace http { namespace client { namespace details { -class winhttp_client; -class winrt_client; -class asio_context; -}}} -namespace websockets { namespace client { namespace details { -class winrt_callback_client; -class wspp_callback_client; -}}} - namespace details { diff --git a/Release/include/cpprest/streams.h b/Release/include/cpprest/streams.h index cb7cd4d0ea..d2923d3774 100644 --- a/Release/include/cpprest/streams.h +++ b/Release/include/cpprest/streams.h @@ -1748,7 +1748,7 @@ class type_parser parse(streams::streambuf buffer) { - return base::_parse_input,std::basic_string>(buffer, _accept_char, _extract_result); + return base::template _parse_input,std::basic_string>(buffer, _accept_char, _extract_result); } private: diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 3bf1fcba23..67d56c1e8f 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -15,9 +15,6 @@ #include "stdafx.h" -#undef min -#undef max - #include "cpprest/asyncrt_utils.h" #include "../common/internal_http_helpers.h" @@ -83,7 +80,7 @@ using utility::conversions::details::to_string; using std::to_string; #endif -#define CRLF std::string("\r\n") +static const std::string CRLF("\r\n"); namespace web { namespace http { @@ -213,14 +210,15 @@ class asio_connection template void async_connect(const Iterator &begin, const Handler &handler) { - std::unique_lock lock(m_socket_lock); - if (!m_closed) - m_socket.async_connect(begin, handler); - else { - lock.unlock(); - handler(boost::asio::error::operation_aborted); - } + std::lock_guard lock(m_socket_lock); + if (!m_closed) { + m_socket.async_connect(begin, handler); + return; + } + } // unlock + + handler(boost::asio::error::operation_aborted); } template @@ -339,7 +337,7 @@ class asio_connection /// } /// /// -class asio_connection_pool : public std::enable_shared_from_this +class asio_connection_pool final : public std::enable_shared_from_this { public: asio_connection_pool() : m_pool_epoch_timer(crossplat::threadpool::shared_instance().service()) @@ -396,24 +394,25 @@ class asio_connection_pool : public std::enable_shared_from_this lock(self.m_lock); if (self.m_prev_epoch == self.m_epoch) { - self.m_connections.clear(); + connections.clear(); self.is_timer_running = false; return; } else { auto prev_epoch = self.m_prev_epoch; - auto erase_end = std::find_if(self.m_connections.begin(), self.m_connections.end(), + auto erase_end = std::find_if(connections.begin(), connections.end(), [prev_epoch](std::pair>& p) { return p.first > prev_epoch; }); - self.m_connections.erase(self.m_connections.begin(), erase_end); + connections.erase(connections.begin(), erase_end); start_epoch_interval(pool); } }); @@ -438,7 +437,7 @@ class asio_client final : public _http_client_communicator , m_start_with_ssl(base_uri().scheme() == U("https") && !this->client_config().proxy().is_specified()) {} - void send_request(const std::shared_ptr &request_ctx) override; + virtual void send_request(const std::shared_ptr &request_ctx) override; void release_connection(std::shared_ptr& conn) { @@ -468,7 +467,7 @@ class asio_client final : public _http_client_communicator const bool m_start_with_ssl; }; -class asio_context : public request_context, public std::enable_shared_from_this +class asio_context final : public request_context, public std::enable_shared_from_this { friend class asio_client; public: @@ -501,7 +500,7 @@ class asio_context : public request_context, public std::enable_shared_from_this return ctx; } - class ssl_proxy_tunnel : public std::enable_shared_from_this + class ssl_proxy_tunnel final : public std::enable_shared_from_this { public: ssl_proxy_tunnel(std::shared_ptr context, std::function)> ssl_tunnel_established) @@ -518,14 +517,15 @@ class asio_context : public request_context, public std::enable_shared_from_this const auto &base_uri = m_context->m_http_client->base_uri(); const auto &host = utility::conversions::to_utf8string(base_uri.host()); - const auto &port = base_uri.port(); + const int portRaw = base_uri.port(); + const int port = (portRaw != 0) ? portRaw : 443; std::ostream request_stream(&m_request); request_stream.imbue(std::locale::classic()); - request_stream << "CONNECT " << host << ":" << ((port != 0) ? port : 443) << " HTTP/1.1" << CRLF; - request_stream << "Host: " << host << ":" << ((port != 0) ? port : 443) << CRLF; - request_stream << "Proxy-Connection: Keep-Alive" << CRLF; + request_stream << "CONNECT " << host << ":" << port << " HTTP/1.1\r\n"; + request_stream << "Host: " << host << ":" << port << CRLF; + request_stream << "Proxy-Connection: Keep-Alive\r\n"; if(m_context->m_http_client->client_config().proxy().credentials().is_set()) { @@ -698,7 +698,7 @@ class asio_context : public request_context, public std::enable_shared_from_this request_stream.imbue(std::locale::classic()); const auto &host = utility::conversions::to_utf8string(base_uri.host()); - request_stream << utility::conversions::to_utf8string(method) << " " << utility::conversions::to_utf8string(encoded_resource) << " " << "HTTP/1.1" << CRLF; + request_stream << utility::conversions::to_utf8string(method) << " " << utility::conversions::to_utf8string(encoded_resource) << " " << "HTTP/1.1\r\n"; int port = base_uri.port(); @@ -766,7 +766,7 @@ class asio_context : public request_context, public std::enable_shared_from_this request_stream << utility::conversions::to_utf8string(::web::http::details::flatten_http_headers(ctx->m_request.headers())); request_stream << extra_headers; // Enforce HTTP connection keep alive (even for the old HTTP/1.0 protocol). - request_stream << "Connection: Keep-Alive" << CRLF << CRLF; + request_stream << "Connection: Keep-Alive\r\n\r\n"; // Start connection timeout timer. if (!ctx->m_timer.has_started()) @@ -1345,7 +1345,7 @@ class asio_context : public request_context, public std::enable_shared_from_this } else { - async_read_until_buffersize(octets + CRLF.size(), // + 2 for crlf + async_read_until_buffersize(octets + CRLF.size(), boost::bind(&asio_context::handle_chunk, shared_from_this(), boost::asio::placeholders::error, octets)); } } diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index f6d343c2b2..ce037a4954 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -23,9 +23,6 @@ #include #endif -#undef min -#undef max - namespace web { namespace http @@ -185,7 +182,7 @@ enum msg_body_type }; // Additional information necessary to track a WinHTTP request. -class winhttp_request_context : public request_context +class winhttp_request_context final : public request_context { public: @@ -248,7 +245,7 @@ class winhttp_request_context : public request_context std::shared_ptr m_self_reference; memory_holder m_body_data; - virtual void cleanup() + void cleanup() { if(m_request_handle != nullptr) { @@ -260,7 +257,7 @@ class winhttp_request_context : public request_context protected: - virtual void finish() + virtual void finish() override { request_context::finish(); assert(m_self_reference != nullptr); @@ -346,7 +343,7 @@ struct ie_proxy_config : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG }; // WinHTTP client. -class winhttp_client : public _http_client_communicator +class winhttp_client final : public _http_client_communicator { public: winhttp_client(http::uri address, http_client_config client_config) @@ -502,17 +499,13 @@ class winhttp_client : public _http_client_communicator } else { + proxy_str = uri.host(); if (uri.port() > 0) { - utility::ostringstream_t ss; - ss.imbue(std::locale::classic()); - ss << uri.host() << _XPLATSTR(":") << uri.port(); - proxy_str = ss.str(); - } - else - { - proxy_str = uri.host(); + proxy_str.push_back(_XPLATSTR(':')); + proxy_str.append(::utility::conversions::details::to_string_t(uri.port())); } + proxy_name = proxy_str.c_str(); } } diff --git a/Release/src/http/client/http_client_winrt.cpp b/Release/src/http/client/http_client_winrt.cpp index e8ee50a018..5a0697b489 100644 --- a/Release/src/http/client/http_client_winrt.cpp +++ b/Release/src/http/client/http_client_winrt.cpp @@ -28,9 +28,6 @@ using namespace std; using namespace Platform; using namespace Microsoft::WRL; -#undef min -#undef max - namespace web { namespace http @@ -41,7 +38,7 @@ namespace details { // Additional information necessary to track a WinRT request. -class winrt_request_context : public request_context +class winrt_request_context final : public request_context { public: @@ -63,7 +60,7 @@ class winrt_request_context : public request_context }; // Implementation of IXMLHTTPRequest2Callback. -class HttpRequestCallback : +class HttpRequestCallback final : public RuntimeClass, IXMLHTTPRequest2Callback, FtmBase> { public: @@ -190,7 +187,7 @@ class HttpRequestCallback : /// read and write operations. The I/O will be done off the UI thread, so there is no risk /// of causing the UI to become unresponsive. /// -class IRequestStream +class IRequestStream final : public Microsoft::WRL::RuntimeClass, ISequentialStream> { public: @@ -279,7 +276,7 @@ class IRequestStream /// read and write operations. The I/O will be done off the UI thread, so there is no risk /// of causing the UI to become unresponsive. /// -class IResponseStream +class IResponseStream final : public Microsoft::WRL::RuntimeClass, ISequentialStream> { public: @@ -353,7 +350,7 @@ class IResponseStream }; // WinRT client. -class winrt_client : public _http_client_communicator +class winrt_client final : public _http_client_communicator { public: winrt_client(http::uri&& address, http_client_config&& client_config) @@ -379,7 +376,7 @@ class winrt_client : public _http_client_communicator protected: // Start sending request. - void send_request(_In_ const std::shared_ptr &request) + virtual void send_request(_In_ const std::shared_ptr &request) override { http_request &msg = request->m_request; auto winrt_context = std::static_pointer_cast(request); diff --git a/Release/src/http/common/http_msg.cpp b/Release/src/http/common/http_msg.cpp index ece2d08c1e..8f218cb913 100644 --- a/Release/src/http/common/http_msg.cpp +++ b/Release/src/http/common/http_msg.cpp @@ -13,9 +13,6 @@ #include "stdafx.h" #include "../common/internal_http_helpers.h" -#undef min -#undef max - using namespace web; using namespace utility; using namespace concurrency; diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index bef47126dc..13b813b858 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -14,9 +14,6 @@ */ #include "stdafx.h" -#undef min -#undef max - #include #include #include @@ -1085,7 +1082,7 @@ will_deref_and_erase_t asio_server_connection::cancel_sending_response_with_erro { auto * context = static_cast(response._get_server_context()); context->m_response_completed.set_exception(eptr); - + // always terminate the connection since error happens return finish_request_response(); } @@ -1096,7 +1093,7 @@ will_deref_and_erase_t asio_server_connection::handle_write_chunked_response(con { return handle_response_written(response, ec); } - + auto readbuf = response._get_impl()->instream().streambuf(); if (readbuf.is_eof()) { diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp index 7d3cea203c..8da74d0083 100644 --- a/Release/src/http/listener/http_server_httpsys.cpp +++ b/Release/src/http/listener/http_server_httpsys.cpp @@ -22,9 +22,6 @@ #include "http_server_httpsys.h" #include "http_server_impl.h" -#undef min -#undef max - using namespace web; using namespace utility; using namespace concurrency; @@ -482,7 +479,7 @@ windows_request_context::~windows_request_context() // Bug is that task_completion_event accesses internal state after setting. // Workaround is to use a lock incurring additional synchronization, if can acquire // the lock then setting of the event has completed. - std::unique_lock lock(m_responseCompletedLock); + std::lock_guard lock(m_responseCompletedLock); // Add a task-based continuation so no exceptions thrown from the task go 'unobserved'. pplx::create_task(m_response_completed).then([](pplx::task t) @@ -759,7 +756,7 @@ void windows_request_context::init_response_callbacks(ShouldWaitForBody shouldWa catch (...) { // Should never get here, if we do there's a chance that a circular reference will cause leaks, - // or worse, undefined behaviour as we don't know who owns 'this' anymore + // or worse, undefined behaviour as we don't know who owns 'this' anymore _ASSERTE(false); m_response = http::http_response(status_codes::InternalError); } @@ -899,7 +896,7 @@ void windows_request_context::transmit_body() if ( !m_sending_in_chunks && !m_transfer_encoding ) { // We are done sending data. - std::unique_lock lock(m_responseCompletedLock); + std::lock_guard lock(m_responseCompletedLock); m_response_completed.set(); return; } @@ -1024,7 +1021,7 @@ void windows_request_context::send_response_body_io_completion(DWORD error_code, /// void windows_request_context::cancel_request_io_completion(DWORD, DWORD) { - std::unique_lock lock(m_responseCompletedLock); + std::lock_guard lock(m_responseCompletedLock); m_response_completed.set_exception(m_except_ptr); } @@ -1047,7 +1044,7 @@ void windows_request_context::cancel_request(std::exception_ptr except_ptr) if(error_code != NO_ERROR && error_code != ERROR_IO_PENDING) { CancelThreadpoolIo(pServer->m_threadpool_io); - std::unique_lock lock(m_responseCompletedLock); + std::lock_guard lock(m_responseCompletedLock); m_response_completed.set_exception(except_ptr); } } @@ -1059,4 +1056,4 @@ std::unique_ptr make_http_httpsys_server() }}}} -#endif +#endif diff --git a/Release/src/json/json.cpp b/Release/src/json/json.cpp index 04ddbe0fe4..e5a6089aea 100644 --- a/Release/src/json/json.cpp +++ b/Release/src/json/json.cpp @@ -13,9 +13,6 @@ #include "stdafx.h" -#undef min -#undef max - using namespace web; bool json::details::g_keep_json_object_unsorted = false; @@ -519,4 +516,3 @@ const web::json::details::json_error_category_impl& web::json::details::json_err #endif return instance; } - diff --git a/Release/src/pch/stdafx.h b/Release/src/pch/stdafx.h index 1532db2f54..93ad966509 100644 --- a/Release/src/pch/stdafx.h +++ b/Release/src/pch/stdafx.h @@ -20,6 +20,7 @@ #endif #ifdef _WIN32 +#define NOMINMAX #ifdef CPPREST_TARGET_XP #include #ifndef _WIN32_WINNT @@ -137,4 +138,4 @@ #if defined(__clang__) #pragma clang diagnostic pop -#endif +#endif diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index 66b85744f4..c670dd0a61 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -20,10 +20,6 @@ #include "ws_client_impl.h" -// These must be undef'ed before including websocketpp because it is not Windows.h safe. -#undef min -#undef max - // Force websocketpp to use C++ std::error_code instead of Boost. #define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_ #if defined(_MSC_VER) @@ -134,22 +130,23 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: ~wspp_callback_client() CPPREST_NOEXCEPT { _ASSERTE(m_state < DESTROYED); - std::unique_lock lock(m_wspp_client_lock); + State localState; + { + std::lock_guard lock(m_wspp_client_lock); + localState = m_state; + } // Unlock the mutex so connect/close can use it. // Now, what states could we be in? - switch (m_state) { + switch (localState) { case DESTROYED: // This should be impossible std::abort(); case CREATED: - lock.unlock(); break; case CLOSED: case CONNECTING: case CONNECTED: case CLOSING: - // Unlock the mutex so connect/close can use it. - lock.unlock(); try { // This will do nothing in the already-connected case From ae50037e020b0a4e4c41009c356994a18e5c0581 Mon Sep 17 00:00:00 2001 From: Adam Duskett Date: Fri, 3 Aug 2018 02:46:05 -0400 Subject: [PATCH 235/438] fix template whitespace syntax (#715) Some files don't have a space inbetween the '<' and '::' charachters, which will cause build failures on older toolchains. Adding a space inbetween these two characters fixes the issue. See http://autobuild.buildroot.net/results/797a9b5fdf6ab0f16f2249324b48292dfab61d9f/build-end.log for more information. --- Release/include/cpprest/details/web_utilities.h | 2 +- Release/include/cpprest/http_client.h | 2 +- Release/include/cpprest/json.h | 2 +- Release/include/cpprest/ws_client.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Release/include/cpprest/details/web_utilities.h b/Release/include/cpprest/details/web_utilities.h index f99a8aa933..c32a58e5e3 100644 --- a/Release/include/cpprest/details/web_utilities.h +++ b/Release/include/cpprest/details/web_utilities.h @@ -22,7 +22,7 @@ class zero_memory_deleter public: _ASYNCRTIMP void operator()(::utility::string_t *data) const; }; -typedef std::unique_ptr<::utility::string_t, zero_memory_deleter> plaintext_string; +typedef std::unique_ptr< ::utility::string_t, zero_memory_deleter> plaintext_string; #if defined(_WIN32) && !defined(CPPREST_TARGET_XP) #if defined(__cplusplus_winrt) diff --git a/Release/include/cpprest/http_client.h b/Release/include/cpprest/http_client.h index a936a23ede..f5ad8fac70 100644 --- a/Release/include/cpprest/http_client.h +++ b/Release/include/cpprest/http_client.h @@ -757,7 +757,7 @@ class http_client private: - std::shared_ptr<::web::http::client::http_pipeline> m_pipeline; + std::shared_ptr< ::web::http::client::http_pipeline> m_pipeline; }; namespace details { diff --git a/Release/include/cpprest/json.h b/Release/include/cpprest/json.h index 07c5450243..dfdeead4f3 100644 --- a/Release/include/cpprest/json.h +++ b/Release/include/cpprest/json.h @@ -301,7 +301,7 @@ namespace json /// Field names associated with JSON values /// Whether to preserve the original order of the fields /// A non-empty JSON object value - static _ASYNCRTIMP json::value __cdecl object(std::vector> fields, bool keep_order = false); + static _ASYNCRTIMP json::value __cdecl object(std::vector> fields, bool keep_order = false); /// /// Creates an empty JSON array diff --git a/Release/include/cpprest/ws_client.h b/Release/include/cpprest/ws_client.h index 9a324cde51..98f933e149 100644 --- a/Release/include/cpprest/ws_client.h +++ b/Release/include/cpprest/ws_client.h @@ -184,7 +184,7 @@ class websocket_client_config /// Vector of all the subprotocols /// If you want all the subprotocols in a comma separated string /// they can be directly looked up in the headers using 'Sec-WebSocket-Protocol'. - _ASYNCRTIMP std::vector<::utility::string_t> subprotocols() const; + _ASYNCRTIMP std::vector< ::utility::string_t> subprotocols() const; /// /// Gets the server certificate validation property. From bcafee3799344572fa06d08687e02319256b80aa Mon Sep 17 00:00:00 2001 From: Wu Yongwei Date: Fri, 3 Aug 2018 14:57:51 +0800 Subject: [PATCH 236/438] Fix a build problem on Clang. (#732) AND_CAPTURE_MEMBER_FUNCTION_POINTERS workaround had a check for GCC, but did not exclude Clang. Clang has a fake GCC version of 4.2, thus caused problems. From 77e184ac7dee11c7ffbfc9b8b36125b4535aeb11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Meusel?= Date: Sat, 4 Aug 2018 01:14:11 +0200 Subject: [PATCH 237/438] set the default open() O_CREAT file permissions to 666 (#736) --- Release/src/streams/fileio_posix.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/src/streams/fileio_posix.cpp b/Release/src/streams/fileio_posix.cpp index 88056e8c38..ce166957ce 100644 --- a/Release/src/streams/fileio_posix.cpp +++ b/Release/src/streams/fileio_posix.cpp @@ -160,7 +160,7 @@ bool _open_fsb_str(_filestream_callback *callback, const char *filename, std::io cmode |= O_CREAT; } - int f = open(name.c_str(), cmode, 0600); + int f = open(name.c_str(), cmode, 0666); _finish_create(f, callback, mode, prot); }); From 8111f2f3128ce5aefad17e80c74a8c39f6d006a9 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 1 Aug 2018 13:11:32 -0700 Subject: [PATCH 238/438] Factor shared threadpool setup/teardown behavior out of platform dependent policies. --- Release/src/pplx/threadpool.cpp | 130 ++++++++++++++++---------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/Release/src/pplx/threadpool.cpp b/Release/src/pplx/threadpool.cpp index d2dc6161a2..f96c2c5109 100644 --- a/Release/src/pplx/threadpool.cpp +++ b/Release/src/pplx/threadpool.cpp @@ -10,7 +10,9 @@ #include "pplx/threadpool.h" #include +#include #include +#include #if defined(__ANDROID__) #include @@ -19,6 +21,32 @@ namespace { +#if defined(__ANDROID__) +// This pointer will be 0-initialized by default (at load time). +std::atomic JVM; + +JNIEnv* get_jvm_env() +{ + abort_if_no_jvm(); + JNIEnv* env = nullptr; + auto result = JVM.load()->AttachCurrentThread(&env, nullptr); + if (result != JNI_OK) + { + throw std::runtime_error("Could not attach to JVM"); + } + + return env; +} + +static void abort_if_no_jvm() +{ + if (JVM == nullptr) + { + __android_log_print(ANDROID_LOG_ERROR, "CPPRESTSDK", "%s", "The CppREST SDK must be initialized before first use on android: https://github.com/Microsoft/cpprestsdk/wiki/How-to-build-for-Android"); + std::abort(); + } +} +#endif // __ANDROID__ struct threadpool_impl final : crossplat::threadpool { @@ -39,6 +67,11 @@ struct threadpool_impl final : crossplat::threadpool } } + threadpool_impl& get_shared() + { + return *this; + } + private: void add_thread() { @@ -50,7 +83,7 @@ struct threadpool_impl final : crossplat::threadpool { crossplat::JVM.load()->DetachCurrentThread(); } -#endif +#endif // __ANDROID__ static void* thread_start(void *arg) CPPREST_NOEXCEPT { @@ -58,95 +91,62 @@ struct threadpool_impl final : crossplat::threadpool // Calling get_jvm_env() here forces the thread to be attached. crossplat::get_jvm_env(); pthread_cleanup_push(detach_from_java, nullptr); -#endif +#endif // __ANDROID__ threadpool_impl* _this = reinterpret_cast(arg); _this->m_service.run(); #if defined(__ANDROID__) pthread_cleanup_pop(true); -#endif +#endif // __ANDROID__ return arg; } std::vector> m_threads; boost::asio::io_service::work m_work; }; -} -namespace crossplat +#if defined(_WIN32) +struct shared_threadpool { -#if defined(__ANDROID__) -// This pointer will be 0-initialized by default (at load time). -std::atomic JVM; + typename std::aligned_union<0, threadpool_impl>::type shared_storage; -static void abort_if_no_jvm() -{ - if (JVM == nullptr) + threadpool_impl& get_shared() { - __android_log_print(ANDROID_LOG_ERROR, "CPPRESTSDK", "%s", "The CppREST SDK must be initialized before first use on android: https://github.com/Microsoft/cpprestsdk/wiki/How-to-build-for-Android"); - std::abort(); + return reinterpret_cast(shared_storage); } -} -JNIEnv* get_jvm_env() -{ - abort_if_no_jvm(); - JNIEnv* env = nullptr; - auto result = JVM.load()->AttachCurrentThread(&env, nullptr); - if (result != JNI_OK) + shared_threadpool(size_t n) { - throw std::runtime_error("Could not attach to JVM"); + ::new (static_cast(&get_shared())) threadpool_impl(n); } - - return env; -} - -threadpool& threadpool::shared_instance() -{ - abort_if_no_jvm(); - static threadpool_impl s_shared(40); - return s_shared; -} - -#elif defined(_WIN32) - -// if linked into a DLL, the threadpool shared instance will be destroyed at DLL_PROCESS_DETACH, -// at which stage joining threads causes deadlock, hence this dance -threadpool& threadpool::shared_instance() -{ - static bool terminate_threads = false; - static struct restore_terminate_threads + ~shared_threadpool() { - ~restore_terminate_threads() - { - boost::asio::detail::thread::set_terminate_threads(terminate_threads); - } - } destroyed_after; - - static threadpool_impl s_shared(40); + // if linked into a DLL, the threadpool shared instance will be + // destroyed at DLL_PROCESS_DETACH, at which stage joining threads + // causes deadlock, hence this dance + bool terminate_threads = boost::asio::detail::thread::terminate_threads(); + boost::asio::detail::thread::set_terminate_threads(true); + get_shared().~threadpool_impl(); + boost::asio::detail::thread::set_terminate_threads(terminate_threads); + } +}; - static struct enforce_terminate_threads - { - ~enforce_terminate_threads() - { - terminate_threads = boost::asio::detail::thread::terminate_threads(); - boost::asio::detail::thread::set_terminate_threads(true); - } - } destroyed_before; +typedef shared_threadpool platform_shared_threadpool; +#else // ^^^ _WIN32 ^^^ // vvv !_WIN32 vvv // +typedef threadpool_impl platform_shared_threadpool; +#endif - return s_shared; } -#else - -// initialize the static shared threadpool +namespace crossplat +{ threadpool& threadpool::shared_instance() { - static threadpool_impl s_shared(40); - return s_shared; +#if defined(__ANDROID__) + abort_if_no_jvm(); +#endif // __ANDROID__ + static platform_shared_threadpool s_shared_impl(40); + return s_shared_impl.get_shared(); } - -#endif - } #if defined(__ANDROID__) @@ -159,4 +159,4 @@ std::unique_ptr crossplat::threadpool::construct(size_t n { return std::unique_ptr(new threadpool_impl(num_threads)); } -#endif +#endif // !defined(CPPREST_EXCLUDE_WEBSOCKETS) || !defined(_WIN32) From 4c6abf33b5dc33c05a93dfb949e5a10ad5903253 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 1 Aug 2018 13:39:25 -0700 Subject: [PATCH 239/438] Add initialize_with_threads feature to control thread count. --- Release/include/pplx/threadpool.h | 12 ++++++++- Release/src/pplx/threadpool.cpp | 41 +++++++++++++++++++++++++------ 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/Release/include/pplx/threadpool.h b/Release/include/pplx/threadpool.h index 919eb75552..dfa3344db8 100644 --- a/Release/include/pplx/threadpool.h +++ b/Release/include/pplx/threadpool.h @@ -57,6 +57,17 @@ class threadpool virtual ~threadpool() = default; + /// + /// Initializes the cpprestsdk threadpool with a custom number of threads + /// + /// + /// This function allows an application (in their main function) to initialize the cpprestsdk + /// threadpool with a custom threadcount. Libraries should avoid calling this function to avoid + /// a diamond problem with multiple consumers attempting to customize the pool. + /// + /// Thrown if the threadpool has already been initialized + static void initialize_with_threads(size_t num_threads); + template CASABLANCA_DEPRECATED("Use `.service().post(task)` directly.") void schedule(T task) @@ -73,4 +84,3 @@ class threadpool }; } - diff --git a/Release/src/pplx/threadpool.cpp b/Release/src/pplx/threadpool.cpp index f96c2c5109..0e92411375 100644 --- a/Release/src/pplx/threadpool.cpp +++ b/Release/src/pplx/threadpool.cpp @@ -42,7 +42,9 @@ static void abort_if_no_jvm() { if (JVM == nullptr) { - __android_log_print(ANDROID_LOG_ERROR, "CPPRESTSDK", "%s", "The CppREST SDK must be initialized before first use on android: https://github.com/Microsoft/cpprestsdk/wiki/How-to-build-for-Android"); + __android_log_print(ANDROID_LOG_ERROR, "CPPRESTSDK", "%s", + "The CppREST SDK must be initialized before first use on android: " + "https://github.com/Microsoft/cpprestsdk/wiki/How-to-build-for-Android"); std::abort(); } } @@ -75,7 +77,8 @@ struct threadpool_impl final : crossplat::threadpool private: void add_thread() { - m_threads.push_back(std::unique_ptr(new boost::asio::detail::thread([&]{ thread_start(this); }))); + m_threads.push_back(std::unique_ptr( + new boost::asio::detail::thread([&]{ thread_start(this); }))); } #if defined(__ANDROID__) @@ -135,17 +138,41 @@ typedef shared_threadpool platform_shared_threadpool; typedef threadpool_impl platform_shared_threadpool; #endif +std::pair initialize_shared_threadpool(size_t num_threads) +{ + static std::once_flag of; + static typename std::aligned_union<0, platform_shared_threadpool>::type storage; + +#if defined(__ANDROID__) + abort_if_no_jvm(); +#endif // __ANDROID__ + platform_shared_threadpool* const ptr = + &reinterpret_cast(storage); + bool initialized_this_time = false; + std::call_once(of, [num_threads, ptr, &initialized_this_time] { + ::new (ptr) platform_shared_threadpool(num_threads); + initialized_this_time = true; + }); + + return {initialized_this_time, ptr}; +} } namespace crossplat { threadpool& threadpool::shared_instance() { -#if defined(__ANDROID__) - abort_if_no_jvm(); -#endif // __ANDROID__ - static platform_shared_threadpool s_shared_impl(40); - return s_shared_impl.get_shared(); + return initialize_shared_threadpool(40).second->get_shared(); +} + + +void threadpool::initialize_with_threads(size_t num_threads) +{ + const auto result = initialize_shared_threadpool(num_threads); + if (!result.first) + { + throw std::runtime_error("the cpprestsdk threadpool has already been initialized"); + } } } From ed2b047229229e501bd019cc6021e4f1011c3516 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 1 Aug 2018 15:02:32 -0700 Subject: [PATCH 240/438] Use double checked locking instead of call_once on Android due to paranoia. --- Release/src/pplx/threadpool.cpp | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/Release/src/pplx/threadpool.cpp b/Release/src/pplx/threadpool.cpp index 0e92411375..9bfeb398ba 100644 --- a/Release/src/pplx/threadpool.cpp +++ b/Release/src/pplx/threadpool.cpp @@ -140,19 +140,38 @@ typedef threadpool_impl platform_shared_threadpool; std::pair initialize_shared_threadpool(size_t num_threads) { - static std::once_flag of; static typename std::aligned_union<0, platform_shared_threadpool>::type storage; - -#if defined(__ANDROID__) - abort_if_no_jvm(); -#endif // __ANDROID__ platform_shared_threadpool* const ptr = &reinterpret_cast(storage); bool initialized_this_time = false; +#if defined(__ANDROID__) + // mutex based implementation due to paranoia about (lack of) call_once support on Android + // remove this if/when call_once is supported + static std::mutex mtx; + static std::atomic initialized; + abort_if_no_jvm(); + if (!initialized.load()) + { + std::lock_guard guard(mtx); + if (!initialized.load()) + { + ::new (static_cast(ptr)) platform_shared_threadpool(num_threads); + initialized.store(true); + initialized_this_time = true; + } + } // also unlock + +#else // ^^^ __ANDROID__ ^^^ // vvv !__ANDROID___ vvv // + static std::once_flag of; + +// #if defined(__ANDROID__) // if call_once can be used for android +// abort_if_no_jvm(); +// #endif // __ANDROID__ std::call_once(of, [num_threads, ptr, &initialized_this_time] { - ::new (ptr) platform_shared_threadpool(num_threads); + ::new (static_cast(ptr)) platform_shared_threadpool(num_threads); initialized_this_time = true; }); +#endif // __ANDROID__ return {initialized_this_time, ptr}; } From 633322537e1057e311984932642513c25499ace6 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Mon, 6 Aug 2018 06:17:23 -0700 Subject: [PATCH 241/438] Workaround Apple clang bugs in constexpr evaluation. (#829) --- Release/src/utilities/asyncrt_utils.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index 893de3729b..72f12ccf10 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -51,7 +51,7 @@ namespace } }; - constexpr to_lower_ch_impl to_lower_ch; + constexpr to_lower_ch_impl to_lower_ch{}; struct eq_lower_ch_impl { @@ -62,7 +62,7 @@ namespace } }; - constexpr eq_lower_ch_impl eq_lower_ch; + constexpr eq_lower_ch_impl eq_lower_ch{}; struct lt_lower_ch_impl { @@ -73,7 +73,7 @@ namespace } }; - constexpr lt_lower_ch_impl lt_lower_ch; + constexpr lt_lower_ch_impl lt_lower_ch{}; } namespace utility From d92e0fe3e83819486009ca7b2eb3ce4dc7411d29 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 9 Aug 2018 13:51:16 -0700 Subject: [PATCH 242/438] Add .clang-format file from vcpkg to cpprestsdk. --- .clang-format | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..4700062c73 --- /dev/null +++ b/.clang-format @@ -0,0 +1,32 @@ +--- +BasedOnStyle: WebKit +Language: Cpp +Standard: Cpp11 + +UseTab: Never +IndentWidth: 4 +ColumnLimit: 120 +PointerAlignment: Left + +BreakBeforeBraces: Allman + +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: false +AlwaysBreakTemplateDeclarations: true +AlignAfterOpenBracket: true +AlignOperands: true +AlignTrailingComments: true +BinPackArguments: false +BinPackParameters: false +BreakBeforeBinaryOperators: None +BreakConstructorInitializersBeforeComma: true +ConstructorInitializerAllOnOneLineOrOnePerLine: true +Cpp11BracedListStyle: true +IndentCaseLabels: true +KeepEmptyLinesAtTheStartOfBlocks: false +NamespaceIndentation: All +PenaltyReturnTypeOnItsOwnLine: 1000 +SpaceAfterTemplateKeyword: false \ No newline at end of file From 7d843a896f8c8eb03db08f53471628aa3bd5c37f Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 9 Aug 2018 13:53:52 -0700 Subject: [PATCH 243/438] Set namespace indentation to none. --- .clang-format | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.clang-format b/.clang-format index 4700062c73..5ef3ed9647 100644 --- a/.clang-format +++ b/.clang-format @@ -1,4 +1,3 @@ ---- BasedOnStyle: WebKit Language: Cpp Standard: Cpp11 @@ -27,6 +26,6 @@ ConstructorInitializerAllOnOneLineOrOnePerLine: true Cpp11BracedListStyle: true IndentCaseLabels: true KeepEmptyLinesAtTheStartOfBlocks: false -NamespaceIndentation: All +NamespaceIndentation: None PenaltyReturnTypeOnItsOwnLine: 1000 -SpaceAfterTemplateKeyword: false \ No newline at end of file +SpaceAfterTemplateKeyword: false From fcbbfa2b1205d13ca4ce57c5a6b14ffc132dbe17 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 9 Aug 2018 13:54:23 -0700 Subject: [PATCH 244/438] Apply clang-format to the asio implementation. --- Release/src/http/client/http_client_asio.cpp | 746 ++++++++++-------- .../src/http/client/x509_cert_utilities.cpp | 316 ++++---- 2 files changed, 560 insertions(+), 502 deletions(-) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 67d56c1e8f..ec41762b3f 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -1,33 +1,33 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* HTTP Library: Client-side APIs. -* -* This file contains a cross platform implementation based on Boost.ASIO. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: Client-side APIs. + * + * This file contains a cross platform implementation based on Boost.ASIO. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#include "cpprest/asyncrt_utils.h" #include "../common/internal_http_helpers.h" +#include "cpprest/asyncrt_utils.h" #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-local-typedef" #pragma clang diagnostic ignored "-Winfinite-recursion" #endif +#include #include #include #include #include -#include #include #if defined(__clang__) #pragma clang diagnostic pop @@ -37,13 +37,13 @@ #error "Cpp rest SDK requires c++11 smart pointer support from boost" #endif -#include "pplx/threadpool.h" -#include "http_client_impl.h" #include "cpprest/base_uri.h" -#include "cpprest/details/x509_cert_utilities.h" #include "cpprest/details/http_helpers.h" -#include +#include "cpprest/details/x509_cert_utilities.h" +#include "http_client_impl.h" +#include "pplx/threadpool.h" #include +#include #if defined(__GNUC__) && !defined(__clang__) @@ -62,7 +62,8 @@ #if _MSC_VER >= 1900 #define AND_CAPTURE_MEMBER_FUNCTION_POINTERS #else -// This bug also afflicts VS2013 which incorrectly reports "warning C4573: the usage of 'symbol' requires the compiler to capture 'this' but the current default capture mode does not allow it" +// This bug also afflicts VS2013 which incorrectly reports "warning C4573: the usage of 'symbol' requires the compiler +// to capture 'this' but the current default capture mode does not allow it" #define AND_CAPTURE_MEMBER_FUNCTION_POINTERS , this #endif @@ -82,13 +83,14 @@ using std::to_string; static const std::string CRLF("\r\n"); -namespace web { namespace http +namespace web +{ +namespace http { namespace client { namespace details { - enum class httpclient_errorcode_context { none = 0, @@ -114,19 +116,15 @@ class asio_connection_pool; class asio_connection { friend class asio_client; + public: asio_connection(boost::asio::io_service& io_service) - : m_socket(io_service), - m_is_reused(false), - m_keep_alive(true), - m_closed(false) - {} - - ~asio_connection() + : m_socket(io_service), m_is_reused(false), m_keep_alive(true), m_closed(false) { - close(); } + ~asio_connection() { close(); } + // This simply instantiates the internal state to support ssl. It does not perform the handshake. void upgrade_to_ssl(const std::function& ssl_context_callback) { @@ -139,7 +137,8 @@ class asio_connection { ssl_context_callback(ssl_context); } - m_ssl_stream = utility::details::make_unique>(m_socket, ssl_context); + m_ssl_stream = utility::details::make_unique>( + m_socket, ssl_context); } void close() @@ -182,9 +181,8 @@ class asio_connection } // These errors tell if connection was closed. - if ((boost::asio::error::eof == ec) - || (boost::asio::error::connection_reset == ec) - || (boost::asio::error::connection_aborted == ec)) + if ((boost::asio::error::eof == ec) || (boost::asio::error::connection_reset == ec) || + (boost::asio::error::connection_aborted == ec)) { return true; } @@ -196,10 +194,10 @@ class asio_connection // server due to inactivity. Unfortunately, the exact error we get // in this case depends on the Boost.Asio version used. #if BOOST_ASIO_VERSION >= 101008 - if (boost::asio::ssl::error::stream_truncated == ec) - return true; + if (boost::asio::ssl::error::stream_truncated == ec) return true; #else // Asio < 1.10.8 didn't have ssl::error::stream_truncated - if (boost::system::error_code(ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ), boost::asio::error::get_ssl_category()) == ec) + if (boost::system::error_code(ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ), + boost::asio::error::get_ssl_category()) == ec) return true; #endif } @@ -207,26 +205,27 @@ class asio_connection return false; } - template - void async_connect(const Iterator &begin, const Handler &handler) + template + void async_connect(const Iterator& begin, const Handler& handler) { { std::lock_guard lock(m_socket_lock); - if (!m_closed) { + if (!m_closed) + { m_socket.async_connect(begin, handler); return; } - } // unlock + } // unlock handler(boost::asio::error::operation_aborted); } - template + template void async_handshake(boost::asio::ssl::stream_base::handshake_type type, - const http_client_config &config, + const http_client_config& config, const std::string& host_name, - const HandshakeHandler &handshake_handler, - const CertificateHandler &cert_handler) + const HandshakeHandler& handshake_handler, + const CertificateHandler& cert_handler) { std::lock_guard lock(m_socket_lock); assert(is_ssl()); @@ -245,14 +244,14 @@ class asio_connection // Check to set host name for Server Name Indication (SNI) if (config.is_tlsext_sni_enabled()) { - SSL_set_tlsext_host_name(m_ssl_stream->native_handle(), const_cast(host_name.data())); + SSL_set_tlsext_host_name(m_ssl_stream->native_handle(), const_cast(host_name.data())); } m_ssl_stream->async_handshake(type, handshake_handler); } - template - void async_write(ConstBufferSequence &buffer, const Handler &writeHandler) + template + void async_write(ConstBufferSequence& buffer, const Handler& writeHandler) { std::lock_guard lock(m_socket_lock); if (m_ssl_stream) @@ -265,8 +264,8 @@ class asio_connection } } - template - void async_read(MutableBufferSequence &buffer, const CompletionCondition &condition, const Handler &readHandler) + template + void async_read(MutableBufferSequence& buffer, const CompletionCondition& condition, const Handler& readHandler) { std::lock_guard lock(m_socket_lock); if (m_ssl_stream) @@ -279,8 +278,8 @@ class asio_connection } } - template - void async_read_until(boost::asio::streambuf &buffer, const std::string &delim, const Handler &readHandler) + template + void async_read_until(boost::asio::streambuf& buffer, const std::string& delim, const Handler& readHandler) { std::lock_guard lock(m_socket_lock); if (m_ssl_stream) @@ -293,10 +292,7 @@ class asio_connection } } - void start_reuse() - { - m_is_reused = true; - } + void start_reuse() { m_is_reused = true; } private: // Guards concurrent access to socket/ssl::stream. This is necessary @@ -304,7 +300,7 @@ class asio_connection // as normal message processing. std::mutex m_socket_lock; tcp::socket m_socket; - std::unique_ptr > m_ssl_stream; + std::unique_ptr> m_ssl_stream; bool m_is_reused; bool m_keep_alive; @@ -340,15 +336,13 @@ class asio_connection class asio_connection_pool final : public std::enable_shared_from_this { public: - asio_connection_pool() : m_pool_epoch_timer(crossplat::threadpool::shared_instance().service()) - {} + asio_connection_pool() : m_pool_epoch_timer(crossplat::threadpool::shared_instance().service()) {} std::shared_ptr acquire() { std::lock_guard lock(m_lock); - if (m_connections.empty()) - return nullptr; + if (m_connections.empty()) return nullptr; auto conn = std::move(m_connections.back().second); m_connections.pop_back(); @@ -360,8 +354,7 @@ class asio_connection_pool final : public std::enable_shared_from_thiscancel(); - if (!connection->keep_alive()) - return; + if (!connection->keep_alive()) return; std::lock_guard lock(m_lock); if (!is_timer_running) @@ -385,14 +378,11 @@ class asio_connection_pool final : public std::enable_shared_from_thism_pool_epoch_timer.expires_from_now(boost::posix_time::seconds(30)); - pool->m_pool_epoch_timer.async_wait([weak_pool](const boost::system::error_code& ec) - { - if (ec) - return; + pool->m_pool_epoch_timer.async_wait([weak_pool](const boost::system::error_code& ec) { + if (ec) return; auto pool = weak_pool.lock(); - if (!pool) - return; + if (!pool) return; auto& self = *pool; auto& connections = self.m_connections; @@ -406,11 +396,11 @@ class asio_connection_pool final : public std::enable_shared_from_this>& p) - { - return p.first > prev_epoch; - }); + auto erase_end = std::find_if(connections.begin(), + connections.end(), + [prev_epoch](std::pair>& p) { + return p.first > prev_epoch; + }); connections.erase(connections.begin(), erase_end); start_epoch_interval(pool); @@ -435,14 +425,12 @@ class asio_client final : public _http_client_communicator , m_resolver(crossplat::threadpool::shared_instance().service()) , m_pool(std::make_shared()) , m_start_with_ssl(base_uri().scheme() == U("https") && !this->client_config().proxy().is_specified()) - {} - - virtual void send_request(const std::shared_ptr &request_ctx) override; - - void release_connection(std::shared_ptr& conn) { - m_pool->release(conn); } + + virtual void send_request(const std::shared_ptr& request_ctx) override; + + void release_connection(std::shared_ptr& conn) { m_pool->release(conn); } std::shared_ptr obtain_connection() { std::shared_ptr conn = m_pool->acquire(); @@ -451,8 +439,7 @@ class asio_client final : public _http_client_communicator { // Pool was empty. Create a new connection conn = std::make_shared(crossplat::threadpool::shared_instance().service()); - if (m_start_with_ssl) - conn->upgrade_to_ssl(this->client_config().get_ssl_context_callback()); + if (m_start_with_ssl) conn->upgrade_to_ssl(this->client_config().get_ssl_context_callback()); } return conn; @@ -462,6 +449,7 @@ class asio_client final : public _http_client_communicator public: tcp::resolver m_resolver; + private: const std::shared_ptr m_pool; const bool m_start_with_ssl; @@ -470,19 +458,21 @@ class asio_client final : public _http_client_communicator class asio_context final : public request_context, public std::enable_shared_from_this { friend class asio_client; + public: - asio_context(const std::shared_ptr<_http_client_communicator> &client, - http_request &request, - const std::shared_ptr &connection) - : request_context(client, request) - , m_content_length(0) - , m_needChunked(false) - , m_timer(client->client_config().timeout()) - , m_connection(connection) + asio_context(const std::shared_ptr<_http_client_communicator>& client, + http_request& request, + const std::shared_ptr& connection) + : request_context(client, request) + , m_content_length(0) + , m_needChunked(false) + , m_timer(client->client_config().timeout()) + , m_connection(connection) #if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) - , m_openssl_failed(false) + , m_openssl_failed(false) #endif - {} + { + } virtual ~asio_context() { @@ -491,7 +481,8 @@ class asio_context final : public request_context, public std::enable_shared_fro std::static_pointer_cast(m_http_client)->release_connection(m_connection); } - static std::shared_ptr create_request_context(std::shared_ptr<_http_client_communicator> &client, http_request &request) + static std::shared_ptr create_request_context(std::shared_ptr<_http_client_communicator>& client, + http_request& request) { auto client_cast(std::static_pointer_cast(client)); auto connection(client_cast->obtain_connection()); @@ -503,9 +494,11 @@ class asio_context final : public request_context, public std::enable_shared_fro class ssl_proxy_tunnel final : public std::enable_shared_from_this { public: - ssl_proxy_tunnel(std::shared_ptr context, std::function)> ssl_tunnel_established) + ssl_proxy_tunnel(std::shared_ptr context, + std::function)> ssl_tunnel_established) : m_ssl_tunnel_established(ssl_tunnel_established), m_context(context) - {} + { + } void start_proxy_connect() { @@ -515,8 +508,8 @@ class asio_context final : public request_context, public std::enable_shared_fro utility::string_t proxy_host = proxy_uri.host(); int proxy_port = proxy_uri.port() == -1 ? 8080 : proxy_uri.port(); - const auto &base_uri = m_context->m_http_client->base_uri(); - const auto &host = utility::conversions::to_utf8string(base_uri.host()); + const auto& base_uri = m_context->m_http_client->base_uri(); + const auto& host = utility::conversions::to_utf8string(base_uri.host()); const int portRaw = base_uri.port(); const int port = (portRaw != 0) ? portRaw : 443; @@ -527,7 +520,7 @@ class asio_context final : public request_context, public std::enable_shared_fro request_stream << "Host: " << host << ":" << port << CRLF; request_stream << "Proxy-Connection: Keep-Alive\r\n"; - if(m_context->m_http_client->client_config().proxy().credentials().is_set()) + if (m_context->m_http_client->client_config().proxy().credentials().is_set()) { request_stream << m_context->generate_basic_proxy_auth_header() << CRLF; } @@ -539,7 +532,11 @@ class asio_context final : public request_context, public std::enable_shared_fro tcp::resolver::query query(utility::conversions::to_utf8string(proxy_host), to_string(proxy_port)); auto client = std::static_pointer_cast(m_context->m_http_client); - client->m_resolver.async_resolve(query, boost::bind(&ssl_proxy_tunnel::handle_resolve, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::iterator)); + client->m_resolver.async_resolve(query, + boost::bind(&ssl_proxy_tunnel::handle_resolve, + shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::iterator)); } private: @@ -553,7 +550,11 @@ class asio_context final : public request_context, public std::enable_shared_fro { m_context->m_timer.reset(); auto endpoint = *endpoints; - m_context->m_connection->async_connect(endpoint, boost::bind(&ssl_proxy_tunnel::handle_tcp_connect, shared_from_this(), boost::asio::placeholders::error, ++endpoints)); + m_context->m_connection->async_connect(endpoint, + boost::bind(&ssl_proxy_tunnel::handle_tcp_connect, + shared_from_this(), + boost::asio::placeholders::error, + ++endpoints)); } } @@ -562,11 +563,15 @@ class asio_context final : public request_context, public std::enable_shared_fro if (!ec) { m_context->m_timer.reset(); - m_context->m_connection->async_write(m_request, boost::bind(&ssl_proxy_tunnel::handle_write_request, shared_from_this(), boost::asio::placeholders::error)); + m_context->m_connection->async_write(m_request, + boost::bind(&ssl_proxy_tunnel::handle_write_request, + shared_from_this(), + boost::asio::placeholders::error)); } else if (endpoints == tcp::resolver::iterator()) { - m_context->report_error("Failed to connect to any resolved proxy endpoint", ec, httpclient_errorcode_context::connect); + m_context->report_error( + "Failed to connect to any resolved proxy endpoint", ec, httpclient_errorcode_context::connect); } else { @@ -576,9 +581,12 @@ class asio_context final : public request_context, public std::enable_shared_fro m_context->m_connection = client->obtain_connection(); auto endpoint = *endpoints; - m_context->m_connection->async_connect(endpoint, boost::bind(&ssl_proxy_tunnel::handle_tcp_connect, shared_from_this(), boost::asio::placeholders::error, ++endpoints)); + m_context->m_connection->async_connect(endpoint, + boost::bind(&ssl_proxy_tunnel::handle_tcp_connect, + shared_from_this(), + boost::asio::placeholders::error, + ++endpoints)); } - } void handle_write_request(const boost::system::error_code& err) @@ -586,11 +594,16 @@ class asio_context final : public request_context, public std::enable_shared_fro if (!err) { m_context->m_timer.reset(); - m_context->m_connection->async_read_until(m_response, CRLF + CRLF, boost::bind(&ssl_proxy_tunnel::handle_status_line, shared_from_this(), boost::asio::placeholders::error)); + m_context->m_connection->async_read_until(m_response, + CRLF + CRLF, + boost::bind(&ssl_proxy_tunnel::handle_status_line, + shared_from_this(), + boost::asio::placeholders::error)); } else { - m_context->report_error("Failed to send connect request to proxy.", err, httpclient_errorcode_context::writebody); + m_context->report_error( + "Failed to send connect request to proxy.", err, httpclient_errorcode_context::writebody); } } @@ -608,13 +621,17 @@ class asio_context final : public request_context, public std::enable_shared_fro if (!response_stream || http_version.substr(0, 5) != "HTTP/") { - m_context->report_error("Invalid HTTP status line during proxy connection", ec, httpclient_errorcode_context::readheader); + m_context->report_error("Invalid HTTP status line during proxy connection", + ec, + httpclient_errorcode_context::readheader); return; } if (status_code != 200) { - m_context->report_error("Expected a 200 response from proxy, received: " + to_string(status_code), ec, httpclient_errorcode_context::readheader); + m_context->report_error("Expected a 200 response from proxy, received: " + to_string(status_code), + ec, + httpclient_errorcode_context::readheader); return; } @@ -646,7 +663,8 @@ class asio_context final : public request_context, public std::enable_shared_fro { if (m_request._cancellation_token().is_canceled()) { - request_context::report_error(make_error_code(std::errc::operation_canceled).value(), "Request canceled by user."); + request_context::report_error(make_error_code(std::errc::operation_canceled).value(), + "Request canceled by user."); return; } @@ -654,36 +672,40 @@ class asio_context final : public request_context, public std::enable_shared_fro std::string proxy_host; int proxy_port = -1; - // There is no support for auto-detection of proxies on non-windows platforms, it must be specified explicitly from the client code. + // There is no support for auto-detection of proxies on non-windows platforms, it must be specified explicitly + // from the client code. if (m_http_client->client_config().proxy().is_specified()) { - proxy_type = m_http_client->base_uri().scheme() == U("https") ? http_proxy_type::ssl_tunnel : http_proxy_type::http; + proxy_type = + m_http_client->base_uri().scheme() == U("https") ? http_proxy_type::ssl_tunnel : http_proxy_type::http; auto proxy = m_http_client->client_config().proxy(); auto proxy_uri = proxy.address(); proxy_port = proxy_uri.port() == -1 ? 8080 : proxy_uri.port(); proxy_host = utility::conversions::to_utf8string(proxy_uri.host()); } - auto start_http_request_flow = [proxy_type, proxy_host, proxy_port AND_CAPTURE_MEMBER_FUNCTION_POINTERS](std::shared_ptr ctx) - { + auto start_http_request_flow = [proxy_type, proxy_host, proxy_port AND_CAPTURE_MEMBER_FUNCTION_POINTERS]( + std::shared_ptr ctx) { if (ctx->m_request._cancellation_token().is_canceled()) { - ctx->request_context::report_error(make_error_code(std::errc::operation_canceled).value(), "Request canceled by user."); + ctx->request_context::report_error(make_error_code(std::errc::operation_canceled).value(), + "Request canceled by user."); return; } - const auto &base_uri = ctx->m_http_client->base_uri(); + const auto& base_uri = ctx->m_http_client->base_uri(); const auto full_uri = uri_builder(base_uri).append(ctx->m_request.relative_uri()).to_uri(); // For a normal http proxy, we need to specify the full request uri, otherwise just specify the resource - auto encoded_resource = proxy_type == http_proxy_type::http ? full_uri.to_string() : full_uri.resource().to_string(); + auto encoded_resource = + proxy_type == http_proxy_type::http ? full_uri.to_string() : full_uri.resource().to_string(); if (encoded_resource.empty()) { encoded_resource = U("/"); } - const auto &method = ctx->m_request.method(); + const auto& method = ctx->m_request.method(); // stop injection of headers via method // resource should be ok, since it's been encoded @@ -696,9 +718,11 @@ class asio_context final : public request_context, public std::enable_shared_fro std::ostream request_stream(&ctx->m_body_buf); request_stream.imbue(std::locale::classic()); - const auto &host = utility::conversions::to_utf8string(base_uri.host()); + const auto& host = utility::conversions::to_utf8string(base_uri.host()); - request_stream << utility::conversions::to_utf8string(method) << " " << utility::conversions::to_utf8string(encoded_resource) << " " << "HTTP/1.1\r\n"; + request_stream << utility::conversions::to_utf8string(method) << " " + << utility::conversions::to_utf8string(encoded_resource) << " " + << "HTTP/1.1\r\n"; int port = base_uri.port(); @@ -711,7 +735,8 @@ class asio_context final : public request_context, public std::enable_shared_fro if (!ctx->m_request.headers().has(header_names::host)) { request_stream << "Host: " << host; - if (!base_uri.is_port_default()) { + if (!base_uri.is_port_default()) + { request_stream << ":" << port; } request_stream << CRLF; @@ -721,7 +746,8 @@ class asio_context final : public request_context, public std::enable_shared_fro std::string extra_headers; // Add header for basic proxy authentication - if (proxy_type == http_proxy_type::http && ctx->m_http_client->client_config().proxy().credentials().is_set()) + if (proxy_type == http_proxy_type::http && + ctx->m_http_client->client_config().proxy().credentials().is_set()) { extra_headers.append(ctx->generate_basic_proxy_auth_header()); } @@ -735,7 +761,8 @@ class asio_context final : public request_context, public std::enable_shared_fro // Check user specified transfer-encoding. std::string transferencoding; - if (ctx->m_request.headers().match(header_names::transfer_encoding, transferencoding) && transferencoding == "chunked") + if (ctx->m_request.headers().match(header_names::transfer_encoding, transferencoding) && + transferencoding == "chunked") { ctx->m_needChunked = true; } @@ -758,12 +785,12 @@ class asio_context final : public request_context, public std::enable_shared_fro if (proxy_type == http_proxy_type::http) { - extra_headers.append( - "Cache-Control: no-store, no-cache\r\n" - "Pragma: no-cache\r\n"); + extra_headers.append("Cache-Control: no-store, no-cache\r\n" + "Pragma: no-cache\r\n"); } - request_stream << utility::conversions::to_utf8string(::web::http::details::flatten_http_headers(ctx->m_request.headers())); + request_stream << utility::conversions::to_utf8string( + ::web::http::details::flatten_http_headers(ctx->m_request.headers())); request_stream << extra_headers; // Enforce HTTP connection keep alive (even for the old HTTP/1.0 protocol). request_stream << "Connection: Keep-Alive\r\n\r\n"; @@ -776,7 +803,8 @@ class asio_context final : public request_context, public std::enable_shared_fro if (ctx->m_connection->is_reused() || proxy_type == http_proxy_type::ssl_tunnel) { - // If socket is a reused connection or we're connected via an ssl-tunneling proxy, try to write the request directly. In both cases we have already established a tcp connection. + // If socket is a reused connection or we're connected via an ssl-tunneling proxy, try to write the + // request directly. In both cases we have already established a tcp connection. ctx->write_request(); } else @@ -790,17 +818,20 @@ class asio_context final : public request_context, public std::enable_shared_fro tcp::resolver::query query(tcp_host, to_string(tcp_port)); auto client = std::static_pointer_cast(ctx->m_http_client); - client->m_resolver.async_resolve(query, boost::bind(&asio_context::handle_resolve, ctx, boost::asio::placeholders::error, boost::asio::placeholders::iterator)); + client->m_resolver.async_resolve(query, + boost::bind(&asio_context::handle_resolve, + ctx, + boost::asio::placeholders::error, + boost::asio::placeholders::iterator)); } - // Register for notification on cancellation to abort this request. + // Register for notification on cancellation to abort this request. if (ctx->m_request._cancellation_token() != pplx::cancellation_token::none()) { // weak_ptr prevents lambda from taking shared ownership of the context. // Otherwise context replacement in the handle_status_line() would leak the objects. std::weak_ptr ctx_weak(ctx); - ctx->m_cancellationRegistration = ctx->m_request._cancellation_token().register_callback([ctx_weak]() - { + ctx->m_cancellationRegistration = ctx->m_request._cancellation_token().register_callback([ctx_weak]() { if (auto ctx_lock = ctx_weak.lock()) { // Shut down transmissions, close the socket and prevent connection from being pooled. @@ -812,8 +843,10 @@ class asio_context final : public request_context, public std::enable_shared_fro if (proxy_type == http_proxy_type::ssl_tunnel) { - // The ssl_tunnel_proxy keeps the context alive and then calls back once the ssl tunnel is established via 'start_http_request_flow' - std::shared_ptr ssl_tunnel = std::make_shared(shared_from_this(), start_http_request_flow); + // The ssl_tunnel_proxy keeps the context alive and then calls back once the ssl tunnel is established via + // 'start_http_request_flow' + std::shared_ptr ssl_tunnel = + std::make_shared(shared_from_this(), start_http_request_flow); ssl_tunnel->start_proxy_connect(); } else @@ -823,7 +856,7 @@ class asio_context final : public request_context, public std::enable_shared_fro } template - void report_exception(const _ExceptionType &e) + void report_exception(const _ExceptionType& e) { report_exception(std::make_exception_ptr(e)); } @@ -836,10 +869,7 @@ class asio_context final : public request_context, public std::enable_shared_fro } private: - void upgrade_to_ssl() - { - m_connection->upgrade_to_ssl(m_http_client->client_config().get_ssl_context_callback()); - } + void upgrade_to_ssl() { m_connection->upgrade_to_ssl(m_http_client->client_config().get_ssl_context_callback()); } std::string generate_basic_auth_header() { @@ -859,7 +889,9 @@ class asio_context final : public request_context, public std::enable_shared_fro return header; } - void report_error(const std::string &message, const boost::system::error_code &ec, httpclient_errorcode_context context = httpclient_errorcode_context::none) + void report_error(const std::string& message, + const boost::system::error_code& ec, + httpclient_errorcode_context context = httpclient_errorcode_context::none) { // By default, errorcodeValue don't need to converted long errorcodeValue = ec.value(); @@ -887,13 +919,13 @@ class asio_context final : public request_context, public std::enable_shared_fro } break; case httpclient_errorcode_context::readheader: - if (ec.default_error_condition().value() == boost::system::errc::no_such_file_or_directory) // bug in boost error_code mapping + if (ec.default_error_condition().value() == + boost::system::errc::no_such_file_or_directory) // bug in boost error_code mapping { errorcodeValue = make_error_code(std::errc::connection_aborted).value(); } break; - default: - break; + default: break; } } request_context::report_error(errorcodeValue, message); @@ -906,7 +938,8 @@ class asio_context final : public request_context, public std::enable_shared_fro { write_request(); } - else if (ec.value() == boost::system::errc::operation_canceled || ec.value() == boost::asio::error::operation_aborted) + else if (ec.value() == boost::system::errc::operation_canceled || + ec.value() == boost::asio::error::operation_aborted) { request_context::report_error(ec.value(), "Request canceled by user."); } @@ -921,7 +954,10 @@ class asio_context final : public request_context, public std::enable_shared_fro m_connection = client->obtain_connection(); auto endpoint = *endpoints; - m_connection->async_connect(endpoint, boost::bind(&asio_context::handle_connect, shared_from_this(), boost::asio::placeholders::error, ++endpoints)); + m_connection->async_connect( + endpoint, + boost::bind( + &asio_context::handle_connect, shared_from_this(), boost::asio::placeholders::error, ++endpoints)); } } @@ -935,7 +971,10 @@ class asio_context final : public request_context, public std::enable_shared_fro { m_timer.reset(); auto endpoint = *endpoints; - m_connection->async_connect(endpoint, boost::bind(&asio_context::handle_connect, shared_from_this(), boost::asio::placeholders::error, ++endpoints)); + m_connection->async_connect( + endpoint, + boost::bind( + &asio_context::handle_connect, shared_from_this(), boost::asio::placeholders::error, ++endpoints)); } } @@ -945,26 +984,28 @@ class asio_context final : public request_context, public std::enable_shared_fro if (m_connection->is_ssl() && !m_connection->is_reused()) { const auto weakCtx = std::weak_ptr(shared_from_this()); - m_connection->async_handshake(boost::asio::ssl::stream_base::client, - m_http_client->client_config(), - utility::conversions::to_utf8string(m_http_client->base_uri().host()), - boost::bind(&asio_context::handle_handshake, shared_from_this(), boost::asio::placeholders::error), - - // Use a weak_ptr since the verify_callback is stored until the connection is destroyed. - // This avoids creating a circular reference since we pool connection objects. - [weakCtx](bool preverified, boost::asio::ssl::verify_context &verify_context) - { - auto this_request = weakCtx.lock(); - if(this_request) - { - return this_request->handle_cert_verification(preverified, verify_context); - } - return false; - }); + m_connection->async_handshake( + boost::asio::ssl::stream_base::client, + m_http_client->client_config(), + utility::conversions::to_utf8string(m_http_client->base_uri().host()), + boost::bind(&asio_context::handle_handshake, shared_from_this(), boost::asio::placeholders::error), + + // Use a weak_ptr since the verify_callback is stored until the connection is destroyed. + // This avoids creating a circular reference since we pool connection objects. + [weakCtx](bool preverified, boost::asio::ssl::verify_context& verify_context) { + auto this_request = weakCtx.lock(); + if (this_request) + { + return this_request->handle_cert_verification(preverified, verify_context); + } + return false; + }); } else { - m_connection->async_write(m_body_buf, boost::bind(&asio_context::handle_write_headers, shared_from_this(), boost::asio::placeholders::error)); + m_connection->async_write( + m_body_buf, + boost::bind(&asio_context::handle_write_headers, shared_from_this(), boost::asio::placeholders::error)); } } @@ -972,7 +1013,9 @@ class asio_context final : public request_context, public std::enable_shared_fro { if (!ec) { - m_connection->async_write(m_body_buf, boost::bind(&asio_context::handle_write_headers, shared_from_this(), boost::asio::placeholders::error)); + m_connection->async_write( + m_body_buf, + boost::bind(&asio_context::handle_write_headers, shared_from_this(), boost::asio::placeholders::error)); } else { @@ -980,7 +1023,7 @@ class asio_context final : public request_context, public std::enable_shared_fro } } - bool handle_cert_verification(bool preverified, boost::asio::ssl::verify_context &verifyCtx) + bool handle_cert_verification(bool preverified, boost::asio::ssl::verify_context& verifyCtx) { // OpenSSL calls the verification callback once per certificate in the chain, // starting with the root CA certificate. The 'leaf', non-Certificate Authority (CA) @@ -988,17 +1031,17 @@ class asio_context final : public request_context, public std::enable_shared_fro // certificate chain, the rest are optional intermediate certificates, followed // finally by the root CA self signed certificate. - const auto &host = utility::conversions::to_utf8string(m_http_client->base_uri().host()); + const auto& host = utility::conversions::to_utf8string(m_http_client->base_uri().host()); #if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) // On OS X, iOS, and Android, OpenSSL doesn't have access to where the OS // stores keychains. If OpenSSL fails we will doing verification at the // end using the whole certificate chain so wait until the 'leaf' cert. // For now return true so OpenSSL continues down the certificate chain. - if(!preverified) + if (!preverified) { m_openssl_failed = true; } - if(m_openssl_failed) + if (m_openssl_failed) { return verify_cert_chain_platform_specific(verifyCtx, host); } @@ -1010,7 +1053,7 @@ class asio_context final : public request_context, public std::enable_shared_fro void handle_write_headers(const boost::system::error_code& ec) { - if(ec) + if (ec) { report_error("Failed to write request headers", ec, httpclient_errorcode_context::writeheader); } @@ -1027,7 +1070,6 @@ class asio_context final : public request_context, public std::enable_shared_fro } } - void handle_write_chunked_body(const boost::system::error_code& ec) { if (ec) @@ -1037,53 +1079,58 @@ class asio_context final : public request_context, public std::enable_shared_fro } m_timer.reset(); - const auto &progress = m_request._get_impl()->_progress_handler(); + const auto& progress = m_request._get_impl()->_progress_handler(); if (progress) { try { (*progress)(message_direction::upload, m_uploaded); } - catch(...) + catch (...) { report_exception(std::current_exception()); return; } } - const auto & chunkSize = m_http_client->client_config().chunksize(); + const auto& chunkSize = m_http_client->client_config().chunksize(); auto readbuf = _get_readbuffer(); - uint8_t *buf = boost::asio::buffer_cast(m_body_buf.prepare(chunkSize + http::details::chunked_encoding::additional_encoding_space)); + uint8_t* buf = boost::asio::buffer_cast( + m_body_buf.prepare(chunkSize + http::details::chunked_encoding::additional_encoding_space)); const auto this_request = shared_from_this(); - readbuf.getn(buf + http::details::chunked_encoding::data_offset, chunkSize).then([this_request, buf, chunkSize AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) - { - size_t readSize = 0; - try - { - readSize = op.get(); - } - catch (...) - { - this_request->report_exception(std::current_exception()); - return; - } + readbuf.getn(buf + http::details::chunked_encoding::data_offset, chunkSize) + .then([this_request, buf, chunkSize AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { + size_t readSize = 0; + try + { + readSize = op.get(); + } + catch (...) + { + this_request->report_exception(std::current_exception()); + return; + } - const size_t offset = http::details::chunked_encoding::add_chunked_delimiters(buf, chunkSize + http::details::chunked_encoding::additional_encoding_space, readSize); - this_request->m_body_buf.commit(readSize + http::details::chunked_encoding::additional_encoding_space); - this_request->m_body_buf.consume(offset); - this_request->m_uploaded += static_cast(readSize); + const size_t offset = http::details::chunked_encoding::add_chunked_delimiters( + buf, chunkSize + http::details::chunked_encoding::additional_encoding_space, readSize); + this_request->m_body_buf.commit(readSize + http::details::chunked_encoding::additional_encoding_space); + this_request->m_body_buf.consume(offset); + this_request->m_uploaded += static_cast(readSize); - if (readSize != 0) - { - this_request->m_connection->async_write(this_request->m_body_buf, - boost::bind(&asio_context::handle_write_chunked_body, this_request, boost::asio::placeholders::error)); - } - else - { - this_request->m_connection->async_write(this_request->m_body_buf, - boost::bind(&asio_context::handle_write_body, this_request, boost::asio::placeholders::error)); - } - }); + if (readSize != 0) + { + this_request->m_connection->async_write(this_request->m_body_buf, + boost::bind(&asio_context::handle_write_chunked_body, + this_request, + boost::asio::placeholders::error)); + } + else + { + this_request->m_connection->async_write( + this_request->m_body_buf, + boost::bind(&asio_context::handle_write_body, this_request, boost::asio::placeholders::error)); + } + }); } void handle_write_large_body(const boost::system::error_code& ec) @@ -1095,14 +1142,14 @@ class asio_context final : public request_context, public std::enable_shared_fro } m_timer.reset(); - const auto &progress = m_request._get_impl()->_progress_handler(); + const auto& progress = m_request._get_impl()->_progress_handler(); if (progress) { try { (*progress)(message_direction::upload, m_uploaded); } - catch(...) + catch (...) { report_exception(std::current_exception()); return; @@ -1110,28 +1157,33 @@ class asio_context final : public request_context, public std::enable_shared_fro } const auto this_request = shared_from_this(); - const auto readSize = static_cast(std::min(static_cast(m_http_client->client_config().chunksize()), m_content_length - m_uploaded)); + const auto readSize = static_cast( + std::min(static_cast(m_http_client->client_config().chunksize()), m_content_length - m_uploaded)); auto readbuf = _get_readbuffer(); - readbuf.getn(boost::asio::buffer_cast(m_body_buf.prepare(readSize)), readSize).then([this_request AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) - { - try - { - const auto actualReadSize = op.get(); - if(actualReadSize == 0) + readbuf.getn(boost::asio::buffer_cast(m_body_buf.prepare(readSize)), readSize) + .then([this_request AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { + try + { + const auto actualReadSize = op.get(); + if (actualReadSize == 0) + { + this_request->report_exception(http_exception( + "Unexpected end of request body stream encountered before Content-Length satisfied.")); + return; + } + this_request->m_uploaded += static_cast(actualReadSize); + this_request->m_body_buf.commit(actualReadSize); + this_request->m_connection->async_write(this_request->m_body_buf, + boost::bind(&asio_context::handle_write_large_body, + this_request, + boost::asio::placeholders::error)); + } + catch (...) { - this_request->report_exception(http_exception("Unexpected end of request body stream encountered before Content-Length satisfied.")); + this_request->report_exception(std::current_exception()); return; } - this_request->m_uploaded += static_cast(actualReadSize); - this_request->m_body_buf.commit(actualReadSize); - this_request->m_connection->async_write(this_request->m_body_buf, boost::bind(&asio_context::handle_write_large_body, this_request, boost::asio::placeholders::error)); - } - catch (...) - { - this_request->report_exception(std::current_exception()); - return; - } - }); + }); } void handle_write_body(const boost::system::error_code& ec) @@ -1139,14 +1191,14 @@ class asio_context final : public request_context, public std::enable_shared_fro if (!ec) { m_timer.reset(); - const auto &progress = m_request._get_impl()->_progress_handler(); + const auto& progress = m_request._get_impl()->_progress_handler(); if (progress) { try { (*progress)(message_direction::upload, m_uploaded); } - catch(...) + catch (...) { report_exception(std::current_exception()); return; @@ -1154,7 +1206,10 @@ class asio_context final : public request_context, public std::enable_shared_fro } // Read until the end of entire headers - m_connection->async_read_until(m_body_buf, CRLF + CRLF, boost::bind(&asio_context::handle_status_line, shared_from_this(), boost::asio::placeholders::error)); + m_connection->async_read_until( + m_body_buf, + CRLF + CRLF, + boost::bind(&asio_context::handle_status_line, shared_from_this(), boost::asio::placeholders::error)); } else { @@ -1202,7 +1257,8 @@ class asio_context final : public request_context, public std::enable_shared_fro if (m_connection->was_reused_and_closed_by_server(ec)) { // Failed to write to socket because connection was already closed while it was in the pool. - // close() here ensures socket is closed in a robust way and prevents the connection from being put to the pool again. + // close() here ensures socket is closed in a robust way and prevents the connection from being put to the + // pool again. m_connection->close(); // Create a new context and copy the request object, completion event and @@ -1253,11 +1309,13 @@ class asio_context final : public request_context, public std::enable_shared_fro m_connection->set_keep_alive(!boost::iequals(value, U("close"))); } - m_response.headers().add(utility::conversions::to_string_t(std::move(name)), utility::conversions::to_string_t(std::move(value))); + m_response.headers().add(utility::conversions::to_string_t(std::move(name)), + utility::conversions::to_string_t(std::move(value))); } } - m_content_length = std::numeric_limits::max(); // Without Content-Length header, size should be same as TCP stream - set it size_t max. + m_content_length = std::numeric_limits::max(); // Without Content-Length header, size should be same as + // TCP stream - set it size_t max. m_response.headers().match(header_names::content_length, m_content_length); if (!this->handle_content_encoding_compression()) @@ -1274,21 +1332,18 @@ class asio_context final : public request_context, public std::enable_shared_fro // note: need to check for 'chunked' here as well, azure storage sends both // transfer-encoding:chunked and content-length:0 (although HTTP says not to) const auto status = m_response.status_code(); - if (m_request.method() == U("HEAD") - || (status >= 100 && status < 200) - || status == status_codes::NoContent - || status == status_codes::NotModified - || (!needChunked && m_content_length == 0)) + if (m_request.method() == U("HEAD") || (status >= 100 && status < 200) || status == status_codes::NoContent || + status == status_codes::NotModified || (!needChunked && m_content_length == 0)) { // we can stop early - no body - const auto &progress = m_request._get_impl()->_progress_handler(); + const auto& progress = m_request._get_impl()->_progress_handler(); if (progress) { try { (*progress)(message_direction::download, 0); } - catch(...) + catch (...) { report_exception(std::current_exception()); return; @@ -1301,18 +1356,25 @@ class asio_context final : public request_context, public std::enable_shared_fro { if (!needChunked) { - async_read_until_buffersize(static_cast(std::min(m_content_length, static_cast(m_http_client->client_config().chunksize()))), - boost::bind(&asio_context::handle_read_content, shared_from_this(), boost::asio::placeholders::error)); + async_read_until_buffersize( + static_cast( + std::min(m_content_length, static_cast(m_http_client->client_config().chunksize()))), + boost::bind( + &asio_context::handle_read_content, shared_from_this(), boost::asio::placeholders::error)); } else { - m_connection->async_read_until(m_body_buf, CRLF, boost::bind(&asio_context::handle_chunk_header, shared_from_this(), boost::asio::placeholders::error)); + m_connection->async_read_until(m_body_buf, + CRLF, + boost::bind(&asio_context::handle_chunk_header, + shared_from_this(), + boost::asio::placeholders::error)); } } } - template - void async_read_until_buffersize(size_t size, const ReadHandler &handler) + template + void async_read_until_buffersize(size_t size, const ReadHandler& handler) { size_t size_to_read = 0; if (m_body_buf.size() < size) @@ -1341,12 +1403,16 @@ class asio_context final : public request_context, public std::enable_shared_fro if (octetLine.fail()) { - report_error("Invalid chunked response header", boost::system::error_code(), httpclient_errorcode_context::readbody); + report_error("Invalid chunked response header", + boost::system::error_code(), + httpclient_errorcode_context::readbody); } else { - async_read_until_buffersize(octets + CRLF.size(), - boost::bind(&asio_context::handle_chunk, shared_from_this(), boost::asio::placeholders::error, octets)); + async_read_until_buffersize( + octets + CRLF.size(), + boost::bind( + &asio_context::handle_chunk, shared_from_this(), boost::asio::placeholders::error, octets)); } } else @@ -1362,7 +1428,7 @@ class asio_context final : public request_context, public std::enable_shared_fro m_timer.reset(); m_downloaded += static_cast(to_read); - const auto &progress = m_request._get_impl()->_progress_handler(); + const auto& progress = m_request._get_impl()->_progress_handler(); if (progress) { try @@ -1385,9 +1451,10 @@ class asio_context final : public request_context, public std::enable_shared_fro { auto writeBuffer = _get_writebuffer(); const auto this_request = shared_from_this(); - if(m_decompressor) + if (m_decompressor) { - auto decompressed = m_decompressor->decompress(boost::asio::buffer_cast(m_body_buf.data()), to_read); + auto decompressed = m_decompressor->decompress( + boost::asio::buffer_cast(m_body_buf.data()), to_read); if (m_decompressor->has_error()) { @@ -1395,11 +1462,16 @@ class asio_context final : public request_context, public std::enable_shared_fro return; } - // It is valid for the decompressor to sometimes return an empty output for a given chunk, the data will be flushed when the next chunk is received + // It is valid for the decompressor to sometimes return an empty output for a given chunk, the data + // will be flushed when the next chunk is received if (decompressed.empty()) { m_body_buf.consume(to_read + CRLF.size()); // consume crlf - m_connection->async_read_until(m_body_buf, CRLF, boost::bind(&asio_context::handle_chunk_header, this_request, boost::asio::placeholders::error)); + m_connection->async_read_until(m_body_buf, + CRLF, + boost::bind(&asio_context::handle_chunk_header, + this_request, + boost::asio::placeholders::error)); } else { @@ -1409,38 +1481,47 @@ class asio_context final : public request_context, public std::enable_shared_fro auto shared_decompressed = std::make_shared(std::move(decompressed)); writeBuffer.putn_nocopy(shared_decompressed->data(), shared_decompressed->size()) - .then([this_request, to_read, shared_decompressed AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) - { + .then([this_request, to_read, shared_decompressed AND_CAPTURE_MEMBER_FUNCTION_POINTERS]( + pplx::task op) { + try + { + op.get(); + this_request->m_body_buf.consume(to_read + CRLF.size()); // consume crlf + this_request->m_connection->async_read_until( + this_request->m_body_buf, + CRLF, + boost::bind(&asio_context::handle_chunk_header, + this_request, + boost::asio::placeholders::error)); + } + catch (...) + { + this_request->report_exception(std::current_exception()); + return; + } + }); + } + } + else + { + writeBuffer.putn_nocopy(boost::asio::buffer_cast(m_body_buf.data()), to_read) + .then([this_request, to_read AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { try { - op.get(); - this_request->m_body_buf.consume(to_read + CRLF.size()); // consume crlf - this_request->m_connection->async_read_until(this_request->m_body_buf, CRLF, boost::bind(&asio_context::handle_chunk_header, this_request, boost::asio::placeholders::error)); + op.wait(); } catch (...) { this_request->report_exception(std::current_exception()); return; } + this_request->m_body_buf.consume(to_read + CRLF.size()); // consume crlf + this_request->m_connection->async_read_until(this_request->m_body_buf, + CRLF, + boost::bind(&asio_context::handle_chunk_header, + this_request, + boost::asio::placeholders::error)); }); - } - } - else - { - writeBuffer.putn_nocopy(boost::asio::buffer_cast(m_body_buf.data()), to_read).then([this_request, to_read AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) - { - try - { - op.wait(); - } - catch (...) - { - this_request->report_exception(std::current_exception()); - return; - } - this_request->m_body_buf.consume(to_read + CRLF.size()); // consume crlf - this_request->m_connection->async_read_until(this_request->m_body_buf, CRLF, boost::bind(&asio_context::handle_chunk_header, this_request, boost::asio::placeholders::error)); - }); } } } @@ -1454,7 +1535,6 @@ class asio_context final : public request_context, public std::enable_shared_fro { auto writeBuffer = _get_writebuffer(); - if (ec) { if (ec == boost::asio::error::eof && m_content_length == std::numeric_limits::max()) @@ -1469,7 +1549,7 @@ class asio_context final : public request_context, public std::enable_shared_fro } m_timer.reset(); - const auto &progress = m_request._get_impl()->_progress_handler(); + const auto& progress = m_request._get_impl()->_progress_handler(); if (progress) { try @@ -1488,11 +1568,13 @@ class asio_context final : public request_context, public std::enable_shared_fro // more data need to be read const auto this_request = shared_from_this(); - auto read_size = static_cast(std::min(static_cast(m_body_buf.size()), m_content_length - m_downloaded)); + auto read_size = static_cast( + std::min(static_cast(m_body_buf.size()), m_content_length - m_downloaded)); - if(m_decompressor) + if (m_decompressor) { - auto decompressed = m_decompressor->decompress(boost::asio::buffer_cast(m_body_buf.data()), read_size); + auto decompressed = + m_decompressor->decompress(boost::asio::buffer_cast(m_body_buf.data()), read_size); if (m_decompressor->has_error()) { @@ -1500,15 +1582,20 @@ class asio_context final : public request_context, public std::enable_shared_fro return; } - // It is valid for the decompressor to sometimes return an empty output for a given chunk, the data will be flushed when the next chunk is received + // It is valid for the decompressor to sometimes return an empty output for a given chunk, the data will + // be flushed when the next chunk is received if (decompressed.empty()) { try { this_request->m_downloaded += static_cast(read_size); - this_request->async_read_until_buffersize(static_cast(std::min(static_cast(this_request->m_http_client->client_config().chunksize()), this_request->m_content_length - this_request->m_downloaded)), - boost::bind(&asio_context::handle_read_content, this_request, boost::asio::placeholders::error)); + this_request->async_read_until_buffersize( + static_cast(std::min( + static_cast(this_request->m_http_client->client_config().chunksize()), + this_request->m_content_length - this_request->m_downloaded)), + boost::bind( + &asio_context::handle_read_content, this_request, boost::asio::placeholders::error)); } catch (...) { @@ -1524,16 +1611,47 @@ class asio_context final : public request_context, public std::enable_shared_fro auto shared_decompressed = std::make_shared(std::move(decompressed)); writeBuffer.putn_nocopy(shared_decompressed->data(), shared_decompressed->size()) - .then([this_request, read_size, shared_decompressed AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) - { + .then([this_request, read_size, shared_decompressed AND_CAPTURE_MEMBER_FUNCTION_POINTERS]( + pplx::task op) { + size_t writtenSize = 0; + try + { + writtenSize = op.get(); + this_request->m_downloaded += static_cast(read_size); + this_request->m_body_buf.consume(writtenSize); + this_request->async_read_until_buffersize( + static_cast(std::min( + static_cast(this_request->m_http_client->client_config().chunksize()), + this_request->m_content_length - this_request->m_downloaded)), + boost::bind(&asio_context::handle_read_content, + this_request, + boost::asio::placeholders::error)); + } + catch (...) + { + this_request->report_exception(std::current_exception()); + return; + } + }); + } + } + else + { + writeBuffer.putn_nocopy(boost::asio::buffer_cast(m_body_buf.data()), read_size) + .then([this_request AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { size_t writtenSize = 0; try { writtenSize = op.get(); - this_request->m_downloaded += static_cast(read_size); + this_request->m_downloaded += static_cast(writtenSize); this_request->m_body_buf.consume(writtenSize); - this_request->async_read_until_buffersize(static_cast(std::min(static_cast(this_request->m_http_client->client_config().chunksize()), this_request->m_content_length - this_request->m_downloaded)), - boost::bind(&asio_context::handle_read_content, this_request, boost::asio::placeholders::error)); + this_request->async_read_until_buffersize( + static_cast(std::min( + static_cast(this_request->m_http_client->client_config().chunksize()), + this_request->m_content_length - this_request->m_downloaded)), + boost::bind(&asio_context::handle_read_content, + this_request, + boost::asio::placeholders::error)); } catch (...) { @@ -1541,28 +1659,6 @@ class asio_context final : public request_context, public std::enable_shared_fro return; } }); - } - } - else - { - writeBuffer.putn_nocopy(boost::asio::buffer_cast(m_body_buf.data()), read_size) - .then([this_request AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) - { - size_t writtenSize = 0; - try - { - writtenSize = op.get(); - this_request->m_downloaded += static_cast(writtenSize); - this_request->m_body_buf.consume(writtenSize); - this_request->async_read_until_buffersize(static_cast(std::min(static_cast(this_request->m_http_client->client_config().chunksize()), this_request->m_content_length - this_request->m_downloaded)), - boost::bind(&asio_context::handle_read_content, this_request, boost::asio::placeholders::error)); - } - catch (...) - { - this_request->report_exception(std::current_exception()); - return; - } - }); } } else @@ -1577,18 +1673,13 @@ class asio_context final : public request_context, public std::enable_shared_fro class timeout_timer { public: - - timeout_timer(const std::chrono::microseconds& timeout) : - m_duration(timeout.count()), - m_state(created), - m_timer(crossplat::threadpool::shared_instance().service()) - {} - - void set_ctx(const std::weak_ptr &ctx) + timeout_timer(const std::chrono::microseconds& timeout) + : m_duration(timeout.count()), m_state(created), m_timer(crossplat::threadpool::shared_instance().service()) { - m_ctx = ctx; } + void set_ctx(const std::weak_ptr& ctx) { m_ctx = ctx; } + void start() { assert(m_state == created); @@ -1597,23 +1688,21 @@ class asio_context final : public request_context, public std::enable_shared_fro m_timer.expires_from_now(m_duration); auto ctx = m_ctx; - m_timer.async_wait([ctx AND_CAPTURE_MEMBER_FUNCTION_POINTERS](const boost::system::error_code& ec) - { - handle_timeout(ec, ctx); - }); + m_timer.async_wait([ctx AND_CAPTURE_MEMBER_FUNCTION_POINTERS](const boost::system::error_code& ec) { + handle_timeout(ec, ctx); + }); } void reset() { assert(m_state == started || m_state == timedout); assert(!m_ctx.expired()); - if(m_timer.expires_from_now(m_duration) > 0) + if (m_timer.expires_from_now(m_duration) > 0) { // The existing handler was canceled so schedule a new one. assert(m_state == started); auto ctx = m_ctx; - m_timer.async_wait([ctx AND_CAPTURE_MEMBER_FUNCTION_POINTERS](const boost::system::error_code& ec) - { + m_timer.async_wait([ctx AND_CAPTURE_MEMBER_FUNCTION_POINTERS](const boost::system::error_code& ec) { handle_timeout(ec, ctx); }); } @@ -1629,10 +1718,9 @@ class asio_context final : public request_context, public std::enable_shared_fro m_timer.cancel(); } - static void handle_timeout(const boost::system::error_code& ec, - const std::weak_ptr &ctx) + static void handle_timeout(const boost::system::error_code& ec, const std::weak_ptr& ctx) { - if(!ec) + if (!ec) { auto shared_ctx = ctx.lock(); if (shared_ctx) @@ -1674,13 +1762,13 @@ class asio_context final : public request_context, public std::enable_shared_fro #endif }; - -std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage(uri&& base_uri, http_client_config&& client_config) +std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage(uri&& base_uri, + http_client_config&& client_config) { return std::make_shared(std::move(base_uri), std::move(client_config)); } -void asio_client::send_request(const std::shared_ptr &request_ctx) +void asio_client::send_request(const std::shared_ptr& request_ctx) { auto ctx = std::static_pointer_cast(request_ctx); @@ -1717,5 +1805,7 @@ pplx::task asio_client::propagate(http_request request) return result_task; } - -}}}} // namespaces +} +} +} +} // namespaces diff --git a/Release/src/http/client/x509_cert_utilities.cpp b/Release/src/http/client/x509_cert_utilities.cpp index 1d4e7137e7..baf1ae8488 100644 --- a/Release/src/http/client/x509_cert_utilities.cpp +++ b/Release/src/http/client/x509_cert_utilities.cpp @@ -1,26 +1,27 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Contains utility functions for helping to verify server certificates in OS X/iOS. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Contains utility functions for helping to verify server certificates in OS X/iOS. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #include "stdafx.h" -#if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) || (defined(_WIN32) && !defined(__cplusplus_winrt) && !defined(_M_ARM) && !defined(CPPREST_EXCLUDE_WEBSOCKETS)) +#if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) || \ + (defined(_WIN32) && !defined(__cplusplus_winrt) && !defined(_M_ARM) && !defined(CPPREST_EXCLUDE_WEBSOCKETS)) #include "cpprest/details/x509_cert_utilities.h" #include #if defined(ANDROID) || defined(__ANDROID__) -#include #include "pplx/threadpool.h" +#include #endif #if defined(__APPLE__) @@ -36,20 +37,26 @@ #include #endif -namespace web { namespace http { namespace client { namespace details { - -static bool verify_X509_cert_chain(const std::vector &certChain, const std::string &hostName); +namespace web +{ +namespace http +{ +namespace client +{ +namespace details +{ +static bool verify_X509_cert_chain(const std::vector& certChain, const std::string& hostName); -bool verify_cert_chain_platform_specific(boost::asio::ssl::verify_context &verifyCtx, const std::string &hostName) +bool verify_cert_chain_platform_specific(boost::asio::ssl::verify_context& verifyCtx, const std::string& hostName) { - X509_STORE_CTX *storeContext = verifyCtx.native_handle(); + X509_STORE_CTX* storeContext = verifyCtx.native_handle(); int currentDepth = X509_STORE_CTX_get_error_depth(storeContext); if (currentDepth != 0) { return true; } - STACK_OF(X509) *certStack = X509_STORE_CTX_get_chain(storeContext); + STACK_OF(X509)* certStack = X509_STORE_CTX_get_chain(storeContext); const int numCerts = sk_X509_num(certStack); if (numCerts < 0) { @@ -60,7 +67,7 @@ bool verify_cert_chain_platform_specific(boost::asio::ssl::verify_context &verif certChain.reserve(numCerts); for (int i = 0; i < numCerts; ++i) { - X509 *cert = sk_X509_value(certStack, i); + X509* cert = sk_X509_value(certStack, i); // Encode into DER format into raw memory. int len = i2d_X509(cert, nullptr); @@ -71,7 +78,7 @@ bool verify_cert_chain_platform_specific(boost::asio::ssl::verify_context &verif std::string certData; certData.resize(len); - unsigned char * buffer = reinterpret_cast(&certData[0]); + unsigned char* buffer = reinterpret_cast(&certData[0]); len = i2d_X509(cert, &buffer); if (len < 0) { @@ -102,9 +109,9 @@ using namespace crossplat; /// occurred when calling a JNI function. /// /// true if JNI call failed, false otherwise. -static bool jni_failed(JNIEnv *env) +static bool jni_failed(JNIEnv* env) { - if(env->ExceptionOccurred()) + if (env->ExceptionOccurred()) { // Clear exception otherwise no other JNI functions can be called. // In the future if we improve error reporting the exception message @@ -114,28 +121,31 @@ static bool jni_failed(JNIEnv *env) } return false; } -template -static bool jni_failed(JNIEnv *env, const java_local_ref &result) +template +static bool jni_failed(JNIEnv* env, const java_local_ref& result) { - if(jni_failed(env) || !result) + if (jni_failed(env) || !result) { return true; } return false; } -static bool jni_failed(JNIEnv *env, const jmethodID &result) +static bool jni_failed(JNIEnv* env, const jmethodID& result) { - if(jni_failed(env) || result == nullptr) + if (jni_failed(env) || result == nullptr) { return true; } return false; } -#define CHECK_JREF(env, obj) if(jni_failed(env, obj)) return false; -#define CHECK_JMID(env, mid) if(jni_failed(env, mid)) return false; -#define CHECK_JNI(env) if(jni_failed(env)) return false; - -bool verify_X509_cert_chain(const std::vector &certChain, const std::string &hostName) +#define CHECK_JREF(env, obj) \ + if (jni_failed(env, obj)) return false; +#define CHECK_JMID(env, mid) \ + if (jni_failed(env, mid)) return false; +#define CHECK_JNI(env) \ + if (jni_failed(env)) return false; + +bool verify_X509_cert_chain(const std::vector& certChain, const std::string& hostName) { JNIEnv* env = get_jvm_env(); @@ -148,24 +158,19 @@ bool verify_X509_cert_chain(const std::vector &certChain, const std // ByteArrayInputStream java_local_ref byteArrayInputStreamClass(env->FindClass("java/io/ByteArrayInputStream")); CHECK_JREF(env, byteArrayInputStreamClass); - jmethodID byteArrayInputStreamConstructorMethod = env->GetMethodID( - byteArrayInputStreamClass.get(), - "", - "([B)V"); + jmethodID byteArrayInputStreamConstructorMethod = + env->GetMethodID(byteArrayInputStreamClass.get(), "", "([B)V"); CHECK_JMID(env, byteArrayInputStreamConstructorMethod); // CertificateFactory java_local_ref certificateFactoryClass(env->FindClass("java/security/cert/CertificateFactory")); CHECK_JREF(env, certificateFactoryClass); jmethodID certificateFactoryGetInstanceMethod = env->GetStaticMethodID( - certificateFactoryClass.get(), - "getInstance", - "(Ljava/lang/String;)Ljava/security/cert/CertificateFactory;"); + certificateFactoryClass.get(), "getInstance", "(Ljava/lang/String;)Ljava/security/cert/CertificateFactory;"); CHECK_JMID(env, certificateFactoryGetInstanceMethod); - jmethodID generateCertificateMethod = env->GetMethodID( - certificateFactoryClass.get(), - "generateCertificate", - "(Ljava/io/InputStream;)Ljava/security/cert/Certificate;"); + jmethodID generateCertificateMethod = env->GetMethodID(certificateFactoryClass.get(), + "generateCertificate", + "(Ljava/io/InputStream;)Ljava/security/cert/Certificate;"); CHECK_JMID(env, generateCertificateMethod); // X509Certificate @@ -176,48 +181,40 @@ bool verify_X509_cert_chain(const std::vector &certChain, const std java_local_ref trustManagerFactoryClass(env->FindClass("javax/net/ssl/TrustManagerFactory")); CHECK_JREF(env, trustManagerFactoryClass); jmethodID trustManagerFactoryGetInstanceMethod = env->GetStaticMethodID( - trustManagerFactoryClass.get(), - "getInstance", - "(Ljava/lang/String;)Ljavax/net/ssl/TrustManagerFactory;"); + trustManagerFactoryClass.get(), "getInstance", "(Ljava/lang/String;)Ljavax/net/ssl/TrustManagerFactory;"); CHECK_JMID(env, trustManagerFactoryGetInstanceMethod); - jmethodID trustManagerFactoryInitMethod = env->GetMethodID( - trustManagerFactoryClass.get(), - "init", - "(Ljava/security/KeyStore;)V"); + jmethodID trustManagerFactoryInitMethod = + env->GetMethodID(trustManagerFactoryClass.get(), "init", "(Ljava/security/KeyStore;)V"); CHECK_JMID(env, trustManagerFactoryInitMethod); - jmethodID trustManagerFactoryGetTrustManagersMethod = env->GetMethodID( - trustManagerFactoryClass.get(), - "getTrustManagers", - "()[Ljavax/net/ssl/TrustManager;"); + jmethodID trustManagerFactoryGetTrustManagersMethod = + env->GetMethodID(trustManagerFactoryClass.get(), "getTrustManagers", "()[Ljavax/net/ssl/TrustManager;"); CHECK_JMID(env, trustManagerFactoryGetTrustManagersMethod); // X509TrustManager java_local_ref X509TrustManagerClass(env->FindClass("javax/net/ssl/X509TrustManager")); CHECK_JREF(env, X509TrustManagerClass); - jmethodID X509TrustManagerCheckServerTrustedMethod = env->GetMethodID( - X509TrustManagerClass.get(), - "checkServerTrusted", - "([Ljava/security/cert/X509Certificate;Ljava/lang/String;)V"); + jmethodID X509TrustManagerCheckServerTrustedMethod = + env->GetMethodID(X509TrustManagerClass.get(), + "checkServerTrusted", + "([Ljava/security/cert/X509Certificate;Ljava/lang/String;)V"); CHECK_JMID(env, X509TrustManagerCheckServerTrustedMethod); // StrictHostnameVerifier - java_local_ref strictHostnameVerifierClass(env->FindClass("org/apache/http/conn/ssl/StrictHostnameVerifier")); + java_local_ref strictHostnameVerifierClass( + env->FindClass("org/apache/http/conn/ssl/StrictHostnameVerifier")); CHECK_JREF(env, strictHostnameVerifierClass); - jmethodID strictHostnameVerifierConstructorMethod = env->GetMethodID(strictHostnameVerifierClass.get(), "", "()V"); + jmethodID strictHostnameVerifierConstructorMethod = + env->GetMethodID(strictHostnameVerifierClass.get(), "", "()V"); CHECK_JMID(env, strictHostnameVerifierConstructorMethod); jmethodID strictHostnameVerifierVerifyMethod = env->GetMethodID( - strictHostnameVerifierClass.get(), - "verify", - "(Ljava/lang/String;Ljava/security/cert/X509Certificate;)V"); + strictHostnameVerifierClass.get(), "verify", "(Ljava/lang/String;Ljava/security/cert/X509Certificate;)V"); CHECK_JMID(env, strictHostnameVerifierVerifyMethod); // Create CertificateFactory java_local_ref XDot509String(env->NewStringUTF("X.509")); CHECK_JREF(env, XDot509String); java_local_ref certificateFactory(env->CallStaticObjectMethod( - certificateFactoryClass.get(), - certificateFactoryGetInstanceMethod, - XDot509String.get())); + certificateFactoryClass.get(), certificateFactoryGetInstanceMethod, XDot509String.get())); CHECK_JREF(env, certificateFactory); // Create Java array to store all the certs in. @@ -229,22 +226,18 @@ bool verify_X509_cert_chain(const std::vector &certChain, const std // 2. Create Certificate using CertificateFactory.generateCertificate // 3. Add Certificate to array int i = 0; - for(const auto &certData : certChain) + for (const auto& certData : certChain) { java_local_ref byteArray(env->NewByteArray(certData.size())); CHECK_JREF(env, byteArray); - env->SetByteArrayRegion(byteArray.get(), 0, certData.size(), reinterpret_cast(certData.c_str())); + env->SetByteArrayRegion(byteArray.get(), 0, certData.size(), reinterpret_cast(certData.c_str())); CHECK_JNI(env); - java_local_ref byteArrayInputStream(env->NewObject( - byteArrayInputStreamClass.get(), - byteArrayInputStreamConstructorMethod, - byteArray.get())); + java_local_ref byteArrayInputStream( + env->NewObject(byteArrayInputStreamClass.get(), byteArrayInputStreamConstructorMethod, byteArray.get())); CHECK_JREF(env, byteArrayInputStream); - java_local_ref cert(env->CallObjectMethod( - certificateFactory.get(), - generateCertificateMethod, - byteArrayInputStream.get())); + java_local_ref cert( + env->CallObjectMethod(certificateFactory.get(), generateCertificateMethod, byteArrayInputStream.get())); CHECK_JREF(env, cert); env->SetObjectArrayElement(certsArray.get(), i, cert.get()); @@ -256,9 +249,7 @@ bool verify_X509_cert_chain(const std::vector &certChain, const std java_local_ref X509String(env->NewStringUTF("X509")); CHECK_JREF(env, X509String); java_local_ref trustFactoryManager(env->CallStaticObjectMethod( - trustManagerFactoryClass.get(), - trustManagerFactoryGetInstanceMethod, - X509String.get())); + trustManagerFactoryClass.get(), trustManagerFactoryGetInstanceMethod, X509String.get())); CHECK_JREF(env, trustFactoryManager); env->CallVoidMethod(trustFactoryManager.get(), trustManagerFactoryInitMethod, nullptr); CHECK_JNI(env); @@ -274,25 +265,18 @@ bool verify_X509_cert_chain(const std::vector &certChain, const std java_local_ref RSAString(env->NewStringUTF("RSA")); CHECK_JREF(env, RSAString); env->CallVoidMethod( - trustManager.get(), - X509TrustManagerCheckServerTrustedMethod, - certsArray.get(), - RSAString.get()); + trustManager.get(), X509TrustManagerCheckServerTrustedMethod, certsArray.get(), RSAString.get()); CHECK_JNI(env); // Verify hostname on certificate according to RFC 2818. - java_local_ref hostnameVerifier(env->NewObject( - strictHostnameVerifierClass.get(), strictHostnameVerifierConstructorMethod)); + java_local_ref hostnameVerifier( + env->NewObject(strictHostnameVerifierClass.get(), strictHostnameVerifierConstructorMethod)); CHECK_JREF(env, hostnameVerifier); java_local_ref hostNameString(env->NewStringUTF(hostName.c_str())); CHECK_JREF(env, hostNameString); java_local_ref cert(env->GetObjectArrayElement(certsArray.get(), 0)); CHECK_JREF(env, cert); - env->CallVoidMethod( - hostnameVerifier.get(), - strictHostnameVerifierVerifyMethod, - hostNameString.get(), - cert.get()); + env->CallVoidMethod(hostnameVerifier.get(), strictHostnameVerifierVerifyMethod, hostNameString.get(), cert.get()); CHECK_JNI(env); return true; @@ -300,64 +284,65 @@ bool verify_X509_cert_chain(const std::vector &certChain, const std #endif #if defined(__APPLE__) -namespace { - // Simple RAII pattern wrapper to perform CFRelease on objects. - template - class cf_ref +namespace +{ +// Simple RAII pattern wrapper to perform CFRelease on objects. +template +class cf_ref +{ +public: + cf_ref(T v) : value(v) { - public: - cf_ref(T v) : value(v) - { - static_assert(sizeof(cf_ref) == sizeof(T), "Code assumes just a wrapper, see usage in CFArrayCreate below."); - } - cf_ref() : value(nullptr) {} - cf_ref(cf_ref &&other) : value(other.value) { other.value = nullptr; } + static_assert(sizeof(cf_ref) == sizeof(T), "Code assumes just a wrapper, see usage in CFArrayCreate below."); + } + cf_ref() : value(nullptr) {} + cf_ref(cf_ref&& other) : value(other.value) { other.value = nullptr; } - ~cf_ref() + ~cf_ref() + { + if (value != nullptr) { - if(value != nullptr) - { - CFRelease(value); - } + CFRelease(value); } + } - T & get() - { - return value; - } - private: - cf_ref(const cf_ref &); - cf_ref & operator=(const cf_ref &); - T value; - }; + T& get() { return value; } + +private: + cf_ref(const cf_ref&); + cf_ref& operator=(const cf_ref&); + T value; +}; } -bool verify_X509_cert_chain(const std::vector &certChain, const std::string &hostName) +bool verify_X509_cert_chain(const std::vector& certChain, const std::string& hostName) { // Build up CFArrayRef with all the certificates. // All this code is basically just to get into the correct structures for the Apple APIs. // Copies are avoided whenever possible. std::vector> certs; - for(const auto & certBuf : certChain) + for (const auto& certBuf : certChain) { - cf_ref certDataRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, - reinterpret_cast(certBuf.c_str()), - certBuf.size(), - kCFAllocatorNull); - if(certDataRef.get() == nullptr) + cf_ref certDataRef = + CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, + reinterpret_cast(certBuf.c_str()), + certBuf.size(), + kCFAllocatorNull); + if (certDataRef.get() == nullptr) { return false; } cf_ref certObj = SecCertificateCreateWithData(nullptr, certDataRef.get()); - if(certObj.get() == nullptr) + if (certObj.get() == nullptr) { return false; } certs.push_back(std::move(certObj)); } - cf_ref certsArray = CFArrayCreate(kCFAllocatorDefault, const_cast(reinterpret_cast(&certs[0])), certs.size(), nullptr); - if(certsArray.get() == nullptr) + cf_ref certsArray = CFArrayCreate( + kCFAllocatorDefault, const_cast(reinterpret_cast(&certs[0])), certs.size(), nullptr); + if (certsArray.get() == nullptr) { return false; } @@ -365,23 +350,21 @@ bool verify_X509_cert_chain(const std::vector &certChain, const std // Create trust management object with certificates and SSL policy. // Note: SecTrustCreateWithCertificates expects the certificate to be // verified is the first element. - cf_ref cfHostName = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, - hostName.c_str(), - kCFStringEncodingASCII, - kCFAllocatorNull); - if(cfHostName.get() == nullptr) + cf_ref cfHostName = CFStringCreateWithCStringNoCopy( + kCFAllocatorDefault, hostName.c_str(), kCFStringEncodingASCII, kCFAllocatorNull); + if (cfHostName.get() == nullptr) { return false; } cf_ref policy = SecPolicyCreateSSL(true /* client side */, cfHostName.get()); cf_ref trust; OSStatus status = SecTrustCreateWithCertificates(certsArray.get(), policy.get(), &trust.get()); - if(status == noErr) + if (status == noErr) { // Perform actual certificate verification. SecTrustResultType trustResult; status = SecTrustEvaluate(trust.get(), &trustResult); - if(status == noErr && (trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed)) + if (status == noErr && (trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed)) { return true; } @@ -392,33 +375,27 @@ bool verify_X509_cert_chain(const std::vector &certChain, const std #endif #if defined(_WIN32) -namespace { - // Helper RAII unique_ptrs to free Windows structures. - struct cert_free_certificate_context - { - void operator()(const CERT_CONTEXT *ctx) const - { - CertFreeCertificateContext(ctx); - } - }; - typedef std::unique_ptr cert_context; - struct cert_free_certificate_chain - { - void operator()(const CERT_CHAIN_CONTEXT *chain) const - { - CertFreeCertificateChain(chain); - } - }; - typedef std::unique_ptr chain_context; +namespace +{ +// Helper RAII unique_ptrs to free Windows structures. +struct cert_free_certificate_context +{ + void operator()(const CERT_CONTEXT* ctx) const { CertFreeCertificateContext(ctx); } +}; +typedef std::unique_ptr cert_context; +struct cert_free_certificate_chain +{ + void operator()(const CERT_CHAIN_CONTEXT* chain) const { CertFreeCertificateChain(chain); } +}; +typedef std::unique_ptr chain_context; } -bool verify_X509_cert_chain(const std::vector &certChain, const std::string &) +bool verify_X509_cert_chain(const std::vector& certChain, const std::string&) { // Create certificate context from server certificate. - cert_context cert(CertCreateCertificateContext( - X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - reinterpret_cast(certChain[0].c_str()), - static_cast(certChain[0].size()))); + cert_context cert(CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + reinterpret_cast(certChain[0].c_str()), + static_cast(certChain[0].size()))); if (cert == nullptr) { return false; @@ -429,27 +406,17 @@ bool verify_X509_cert_chain(const std::vector &certChain, const std ZeroMemory(¶ms, sizeof(params)); params.cbSize = sizeof(CERT_CHAIN_PARA); params.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; - LPSTR usages [] = - { - (LPSTR)szOID_PKIX_KP_SERVER_AUTH, + LPSTR usages[] = {(LPSTR)szOID_PKIX_KP_SERVER_AUTH, - // For older servers and to match IE. - (LPSTR)szOID_SERVER_GATED_CRYPTO, - (LPSTR)szOID_SGC_NETSCAPE - }; + // For older servers and to match IE. + (LPSTR)szOID_SERVER_GATED_CRYPTO, + (LPSTR)szOID_SGC_NETSCAPE}; params.RequestedUsage.Usage.cUsageIdentifier = std::extent::value; params.RequestedUsage.Usage.rgpszUsageIdentifier = usages; PCCERT_CHAIN_CONTEXT chainContext; chain_context chain; if (!CertGetCertificateChain( - nullptr, - cert.get(), - nullptr, - nullptr, - ¶ms, - CERT_CHAIN_REVOCATION_CHECK_CHAIN, - nullptr, - &chainContext)) + nullptr, cert.get(), nullptr, nullptr, ¶ms, CERT_CHAIN_REVOCATION_CHECK_CHAIN, nullptr, &chainContext)) { return false; } @@ -464,8 +431,9 @@ bool verify_X509_cert_chain(const std::vector &certChain, const std return true; } #endif - - -}}}} +} +} +} +} #endif From f884d916ee196324711ac26f06e43aa52af83585 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Thu, 9 Aug 2018 17:11:23 -0700 Subject: [PATCH 245/438] Attempt to repair VS2013 builds. (#833) --- Release/include/cpprest/asyncrt_utils.h | 6 +++--- Release/include/cpprest/http_headers.h | 26 ++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index 3fbebd7d95..5978a2b051 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -356,7 +356,7 @@ namespace details /// Our own implementation of alpha numeric instead of std::isalnum to avoid /// taking global lock for performance reasons. /// - inline bool __cdecl is_alnum(const unsigned char uch) noexcept + inline bool __cdecl is_alnum(const unsigned char uch) CPPREST_NOEXCEPT { // test if uch is an alnum character // special casing char to avoid branches static constexpr bool is_alnum_table[UCHAR_MAX + 1] = @@ -379,7 +379,7 @@ namespace details /// Our own implementation of alpha numeric instead of std::isalnum to avoid /// taking global lock for performance reasons. /// - inline bool __cdecl is_alnum(const char ch) noexcept + inline bool __cdecl is_alnum(const char ch) CPPREST_NOEXCEPT { return (is_alnum(static_cast(ch))); } @@ -389,7 +389,7 @@ namespace details /// taking global lock for performance reasons. /// template - inline bool __cdecl is_alnum(Elem ch) noexcept + inline bool __cdecl is_alnum(Elem ch) CPPREST_NOEXCEPT { // assumes 'x' == L'x' for the ASCII range typedef typename std::make_unsigned::type UElem; diff --git a/Release/include/cpprest/http_headers.h b/Release/include/cpprest/http_headers.h index 2bc1975acd..c2e35f6079 100644 --- a/Release/include/cpprest/http_headers.h +++ b/Release/include/cpprest/http_headers.h @@ -79,19 +79,19 @@ class http_headers /// /// STL-style typedefs /// - 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; + typedef inner_container::key_type key_type; + typedef inner_container::key_compare key_compare; + typedef inner_container::allocator_type allocator_type; + typedef inner_container::size_type size_type; + typedef inner_container::difference_type difference_type; + typedef inner_container::pointer pointer; + typedef inner_container::const_pointer const_pointer; + typedef inner_container::reference reference; + typedef inner_container::const_reference const_reference; + typedef inner_container::iterator iterator; + typedef inner_container::const_iterator const_iterator; + typedef inner_container::reverse_iterator reverse_iterator; + typedef inner_container::const_reverse_iterator const_reverse_iterator; /// /// Constructs an empty set of HTTP headers. From 6f65e878b3936143dd27679bfa17406799d9e294 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Thu, 9 Aug 2018 20:50:09 -0700 Subject: [PATCH 246/438] Implement host override of CN checking in the WinHTTP backend (#824) * Implement CN overrides via the Host: header in the WinHTTP backend. * Repair lack of fallback CN verification on Windows. * Set security settings even for non-HTTPS URIs in WinHTTP, in case we get upgraded to SSL/TLS later. * Add test to make sure this doesn't explode. * Repair CPPREST_EXCLUDE_WEBSOCKETS support. * Move x509_cert_utilities.h out of public headers. --- Release/src/http/client/http_client_asio.cpp | 16 +- .../src/http/client/http_client_winhttp.cpp | 291 ++++++++++++++---- .../src/http/client/x509_cert_utilities.cpp | 97 +++--- .../http/common}/x509_cert_utilities.h | 51 ++- .../src/websockets/client/ws_client_wspp.cpp | 18 +- .../functional/http/client/outside_tests.cpp | 33 +- 6 files changed, 374 insertions(+), 132 deletions(-) rename Release/{include/cpprest/details => src/http/common}/x509_cert_utilities.h (51%) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index ec41762b3f..d3002dfc09 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -39,7 +39,7 @@ #include "cpprest/base_uri.h" #include "cpprest/details/http_helpers.h" -#include "cpprest/details/x509_cert_utilities.h" +#include "../common/x509_cert_utilities.h" #include "http_client_impl.h" #include "pplx/threadpool.h" #include @@ -468,7 +468,7 @@ class asio_context final : public request_context, public std::enable_shared_fro , m_needChunked(false) , m_timer(client->client_config().timeout()) , m_connection(connection) -#if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) +#ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE , m_openssl_failed(false) #endif { @@ -1032,11 +1032,11 @@ class asio_context final : public request_context, public std::enable_shared_fro // finally by the root CA self signed certificate. const auto& host = utility::conversions::to_utf8string(m_http_client->base_uri().host()); -#if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) - // On OS X, iOS, and Android, OpenSSL doesn't have access to where the OS - // stores keychains. If OpenSSL fails we will doing verification at the - // end using the whole certificate chain so wait until the 'leaf' cert. - // For now return true so OpenSSL continues down the certificate chain. +#ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE + // Attempt to use platform certificate validation when it is available: + // If OpenSSL fails we will doing verification at the end using the whole certificate chain, + // so wait until the 'leaf' cert. For now return true so OpenSSL continues down the certificate + // chain. if (!preverified) { m_openssl_failed = true; @@ -1757,7 +1757,7 @@ class asio_context final : public request_context, public std::enable_shared_fro boost::asio::streambuf m_body_buf; std::shared_ptr m_connection; -#if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) +#ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE bool m_openssl_failed; #endif }; diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index ce037a4954..83a60d6ce5 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -15,14 +15,55 @@ #include "stdafx.h" #include +#include #include "cpprest/http_headers.h" +#include "../common/x509_cert_utilities.h" #include "http_client_impl.h" #ifndef CPPREST_TARGET_XP #include #endif +namespace +{ +struct security_failure_message +{ + std::uint32_t flag; + const char * text; +}; + +constexpr security_failure_message g_security_failure_messages[] = { + { WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED, + "WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED failed to check revocation status."}, + { WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT, + "WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT SSL certificate is invalid."}, + { WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED, + "WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED SSL certificate was revoked."}, + { WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA, + "WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA SSL invalid CA."}, + { WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID, + "WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID SSL common name does not match."}, + { WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID, + "WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID SLL certificate is expired."}, + { WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR, + "WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR internal error."}, +}; + +std::string generate_security_failure_message(std::uint32_t flags) +{ + std::string result("SSL Error:"); + for (const auto& message : g_security_failure_messages) { + if (flags & message.flag) { + result.push_back(' '); + result.append(message.text); + } + } + + return result; +} + +} // unnamed namespace namespace web { namespace http @@ -255,6 +296,124 @@ class winhttp_request_context final : public request_context } } + void install_custom_cn_check(const utility::string_t& customHost) + { + m_customCnCheck = customHost; + utility::details::inplace_tolower(m_customCnCheck); + } + + void on_send_request_validate_cn() + { + if (m_customCnCheck.empty()) + { + // no custom validation selected; either we've delegated that to winhttp or + // certificate checking is completely disabled + return; + } + + winhttp_cert_context certContext; + DWORD bufferSize = sizeof(certContext.raw); + if (!WinHttpQueryOption( + m_request_handle, + WINHTTP_OPTION_SERVER_CERT_CONTEXT, + &certContext.raw, + &bufferSize)) + { + auto errorCode = GetLastError(); + if (errorCode == HRESULT_CODE(WININET_E_INCORRECT_HANDLE_STATE)) + { + // typically happens when given a custom host with an initially HTTP connection + return; + } + + report_error(errorCode, build_error_msg(errorCode, + "WinHttpQueryOption WINHTTP_OPTION_SERVER_CERT_CONTEXT")); + cleanup(); + return; + } + + const auto encodedFirst = certContext.raw->pbCertEncoded; + const auto encodedLast = encodedFirst + certContext.raw->cbCertEncoded; + if (certContext.raw->cbCertEncoded == m_cachedEncodedCert.size() + && std::equal(encodedFirst, encodedLast, m_cachedEncodedCert.begin())) + { + // already validated OK + return; + } + + char oidPkixKpServerAuth[] = szOID_PKIX_KP_SERVER_AUTH; + char oidServerGatedCrypto[] = szOID_SERVER_GATED_CRYPTO; + char oidSgcNetscape[] = szOID_SGC_NETSCAPE; + char *chainUses[] = { + oidPkixKpServerAuth, + oidServerGatedCrypto, + oidSgcNetscape, + }; + + winhttp_cert_chain_context chainContext; + CERT_CHAIN_PARA chainPara = {sizeof(chainPara)}; + chainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; + chainPara.RequestedUsage.Usage.cUsageIdentifier = + sizeof(chainUses) / sizeof(char *); + chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = chainUses; + + // note that the following chain only checks the end certificate; we + // assume WinHTTP already validated everything but the common name. + if (!CertGetCertificateChain( + NULL, + certContext.raw, + nullptr, + certContext.raw->hCertStore, + &chainPara, + CERT_CHAIN_CACHE_END_CERT, + NULL, + &chainContext.raw)) + { + auto errorCode = GetLastError(); + report_error(errorCode, build_error_msg(errorCode, + "CertGetCertificateChain")); + cleanup(); + return; + } + + HTTPSPolicyCallbackData policyData = { + {sizeof(policyData)}, + AUTHTYPE_SERVER, + // we assume WinHTTP already checked these: + 0x00000080 /* SECURITY_FLAG_IGNORE_REVOCATION */ + | 0x00000100 /* SECURITY_FLAG_IGNORE_UNKNOWN_CA */ + | 0x00000200 /* SECURITY_FLAG_IGNORE_WRONG_USAGE */ + | 0x00002000 /* SECURITY_FLAG_IGNORE_CERT_DATE_INVALID */, + &m_customCnCheck[0], + }; + CERT_CHAIN_POLICY_PARA policyPara = {sizeof(policyPara)}; + policyPara.pvExtraPolicyPara = &policyData; + + CERT_CHAIN_POLICY_STATUS policyStatus = {sizeof(policyStatus)}; + if (!CertVerifyCertificateChainPolicy( + CERT_CHAIN_POLICY_SSL, + chainContext.raw, + &policyPara, + &policyStatus)) + { + auto errorCode = GetLastError(); + report_error(errorCode, build_error_msg(errorCode, + "CertVerifyCertificateChainPolicy")); + cleanup(); + return; + } + + if (policyStatus.dwError) + { + report_error(policyStatus.dwError, + build_error_msg(policyStatus.dwError, "Incorrect common name")); + cleanup(); + return; + } + + m_cachedEncodedCert.assign(encodedFirst, encodedLast); + } + protected: virtual void finish() override @@ -267,6 +426,9 @@ class winhttp_request_context final : public request_context private: + utility::string_t m_customCnCheck; + std::vector m_cachedEncodedCert; + // Can only create on the heap using factory function. winhttp_request_context(const std::shared_ptr<_http_client_communicator> &client, const http_request &request) : request_context(client, request), @@ -393,14 +555,6 @@ class winhttp_client final : public _http_client_communicator protected: - unsigned long report_failure(const utility::string_t& errorMessage) - { - // Should we log? - CASABLANCA_UNREFERENCED_PARAMETER(errorMessage); - - return GetLastError(); - } - // Open session and connection with the server. unsigned long open() { @@ -519,7 +673,7 @@ class winhttp_client final : public _http_client_communicator WINHTTP_FLAG_ASYNC); if(!m_hSession) { - return report_failure(_XPLATSTR("Error opening session")); + return GetLastError(); } // Set timeouts. @@ -531,7 +685,7 @@ class winhttp_client final : public _http_client_communicator milliseconds, milliseconds)) { - return report_failure(_XPLATSTR("Error setting timeouts")); + return GetLastError(); } if(config.guarantee_order()) @@ -540,7 +694,7 @@ class winhttp_client final : public _http_client_communicator DWORD maxConnections = 1; if(!WinHttpSetOption(m_hSession, WINHTTP_OPTION_MAX_CONNS_PER_SERVER, &maxConnections, sizeof(maxConnections))) { - return report_failure(_XPLATSTR("Error setting options")); + return GetLastError(); } } @@ -552,7 +706,7 @@ class winhttp_client final : public _http_client_communicator win32_result = ::WinHttpSetOption(m_hSession, WINHTTP_OPTION_SECURE_PROTOCOLS, &secure_protocols, sizeof(secure_protocols)); if(FALSE == win32_result) { - return report_failure(_XPLATSTR("Error setting session options")); + return GetLastError(); } #endif @@ -562,10 +716,13 @@ class winhttp_client final : public _http_client_communicator if(WINHTTP_INVALID_STATUS_CALLBACK == WinHttpSetStatusCallback( m_hSession, &winhttp_client::completion_callback, - WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS | WINHTTP_CALLBACK_FLAG_HANDLES | WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, + WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS + | WINHTTP_CALLBACK_FLAG_HANDLES + | WINHTTP_CALLBACK_FLAG_SECURE_FAILURE + | WINHTTP_CALLBACK_FLAG_SEND_REQUEST, 0)) { - return report_failure(_XPLATSTR("Error registering callback")); + return GetLastError(); } // Open connection. @@ -578,7 +735,7 @@ class winhttp_client final : public _http_client_communicator if(m_hConnection == nullptr) { - return report_failure(_XPLATSTR("Error opening connection")); + return GetLastError(); } m_opened = true; @@ -600,6 +757,7 @@ class winhttp_client final : public _http_client_communicator } http_request &msg = request->m_request; + http_headers &headers = msg.headers(); std::shared_ptr winhttp_context = std::static_pointer_cast(request); std::weak_ptr weak_winhttp_context = winhttp_context; @@ -659,18 +817,6 @@ class winhttp_client final : public _http_client_communicator return; } - // Enable the certificate revocation check - if (m_secure && client_config().validate_certificates()) - { - DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; - if (!WinHttpSetOption(winhttp_context->m_request_handle, WINHTTP_OPTION_ENABLE_FEATURE, &dwEnableSSLRevocOpt, sizeof(dwEnableSSLRevocOpt))) - { - auto errorCode = GetLastError(); - request->report_error(errorCode, build_error_msg(errorCode, "Error enabling SSL revocation check")); - return; - } - } - if(proxy_info_required) { auto result = WinHttpSetOption( @@ -707,24 +853,49 @@ class winhttp_client final : public _http_client_communicator } // Check to turn off server certificate verification. - if(!client_config().validate_certificates()) + DWORD ignoredCertificateValidationSteps = 0; + if (client_config().validate_certificates()) + { + // if we are validating certificates, also turn on revocation checking + DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION; + if (!WinHttpSetOption(winhttp_context->m_request_handle, WINHTTP_OPTION_ENABLE_FEATURE, + &dwEnableSSLRevocOpt, sizeof(dwEnableSSLRevocOpt))) + { + auto errorCode = GetLastError(); + request->report_error(errorCode, build_error_msg(errorCode, "Error enabling SSL revocation check")); + return; + } + + // check if the user has overridden the desired Common Name with the host header + const auto hostHeader = headers.find(_XPLATSTR("Host")); + if (hostHeader != headers.end()) + { + const auto& requestHost = hostHeader->second; + if (!utility::details::str_iequal(requestHost, m_uri.host())) + { + winhttp_context->install_custom_cn_check(requestHost); + ignoredCertificateValidationSteps = SECURITY_FLAG_IGNORE_CERT_CN_INVALID; + } + } + } + else { - DWORD data = SECURITY_FLAG_IGNORE_UNKNOWN_CA + ignoredCertificateValidationSteps = SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE; + } - auto result = WinHttpSetOption( + if(ignoredCertificateValidationSteps + && !WinHttpSetOption( winhttp_context->m_request_handle, WINHTTP_OPTION_SECURITY_FLAGS, - &data, - sizeof(data)); - if(!result) - { - auto errorCode = GetLastError(); - request->report_error(errorCode, build_error_msg(errorCode, "Setting ignore server certificate verification")); - return; - } + &ignoredCertificateValidationSteps, + sizeof(ignoredCertificateValidationSteps))) + { + auto errorCode = GetLastError(); + request->report_error(errorCode, build_error_msg(errorCode, "Setting ignore server certificate verification")); + return; } const size_t content_length = msg._get_impl()->_get_content_length(); @@ -751,7 +922,7 @@ class winhttp_client final : public _http_client_communicator } } - utility::string_t flattened_headers = web::http::details::flatten_http_headers(msg.headers()); + utility::string_t flattened_headers = web::http::details::flatten_http_headers(headers); flattened_headers += winhttp_context->get_accept_encoding_header(); // Add headers. @@ -1218,7 +1389,9 @@ class winhttp_client final : public _http_client_communicator std::weak_ptr* p_weak_request_context = reinterpret_cast *>(context); if (p_weak_request_context == nullptr) + { return; + } if (statusCode == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) { @@ -1230,8 +1403,10 @@ class winhttp_client final : public _http_client_communicator auto p_request_context = p_weak_request_context->lock(); if (!p_request_context) + { // The request context was already released, probably due to cancellation return; + } switch (statusCode) { @@ -1254,7 +1429,7 @@ class winhttp_client final : public _http_client_communicator } p_request_context->report_error(errorCode, build_error_msg(error_result)); - break; + return; } case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE : { @@ -1288,25 +1463,15 @@ class winhttp_client final : public _http_client_communicator p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpReceiveResponse")); } } - break; + return; } + case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST: + p_request_context->on_send_request_validate_cn(); + return; case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE: - { - auto *flagsPtr = reinterpret_cast(statusInfo); - auto flags = *flagsPtr; - - std::string err = "SSL error: "; - if (flags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED) err += "WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED failed to check revocation status. "; - if (flags & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT) err += "WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT SSL certificate is invalid. "; - if (flags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED) err += "WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED SSL certificate was revoked. "; - if (flags & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA) err += "WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA SSL invalid CA. "; - if (flags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID) err += "WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID SSL common name does not match. "; - if (flags & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID) err += "WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID SLL certificate is expired. "; - if (flags & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR) err += "WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR internal error. "; - - p_request_context->report_exception(web::http::http_exception(std::move(err))); - break; - } + p_request_context->report_exception(web::http::http_exception( + generate_security_failure_message(*reinterpret_cast(statusInfo)))); + return; case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE : { DWORD bytesWritten = *((DWORD *)statusInfo); @@ -1347,7 +1512,7 @@ class winhttp_client final : public _http_client_communicator p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpReceiveResponse")); } } - break; + return; } case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE : { @@ -1411,7 +1576,7 @@ class winhttp_client final : public _http_client_communicator // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4 read_next_response_chunk(p_request_context.get(), 0, true); - break; + return; } case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE : { @@ -1459,7 +1624,7 @@ class winhttp_client final : public _http_client_communicator p_request_context->complete_request(p_request_context->m_downloaded); } - break; + return; } case WINHTTP_CALLBACK_STATUS_READ_COMPLETE : { @@ -1483,7 +1648,7 @@ class winhttp_client final : public _http_client_communicator if (bytesRead == 0) { p_request_context->complete_request(p_request_context->m_downloaded); - break; + return; } auto writebuf = p_request_context->_get_writebuffer(); @@ -1544,9 +1709,9 @@ class winhttp_client final : public _http_client_communicator read_next_response_chunk(p_request_context.get(), bytesRead); }); } - break; + return; } - } + } } std::atomic m_opened; diff --git a/Release/src/http/client/x509_cert_utilities.cpp b/Release/src/http/client/x509_cert_utilities.cpp index baf1ae8488..0a7a762d50 100644 --- a/Release/src/http/client/x509_cert_utilities.cpp +++ b/Release/src/http/client/x509_cert_utilities.cpp @@ -12,11 +12,11 @@ ****/ #include "stdafx.h" +#include "../common/x509_cert_utilities.h" -#if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) || \ - (defined(_WIN32) && !defined(__cplusplus_winrt) && !defined(_M_ARM) && !defined(CPPREST_EXCLUDE_WEBSOCKETS)) +#ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE -#include "cpprest/details/x509_cert_utilities.h" +#include #include #if defined(ANDROID) || defined(__ANDROID__) @@ -32,11 +32,6 @@ #include #endif -#if defined(_WIN32) -#include -#include -#endif - namespace web { namespace http @@ -375,55 +370,67 @@ bool verify_X509_cert_chain(const std::vector& certChain, const std #endif #if defined(_WIN32) -namespace -{ -// Helper RAII unique_ptrs to free Windows structures. -struct cert_free_certificate_context -{ - void operator()(const CERT_CONTEXT* ctx) const { CertFreeCertificateContext(ctx); } -}; -typedef std::unique_ptr cert_context; -struct cert_free_certificate_chain -{ - void operator()(const CERT_CHAIN_CONTEXT* chain) const { CertFreeCertificateChain(chain); } -}; -typedef std::unique_ptr chain_context; -} - -bool verify_X509_cert_chain(const std::vector& certChain, const std::string&) +bool verify_X509_cert_chain(const std::vector& certChain, const std::string& hostname) { // Create certificate context from server certificate. - cert_context cert(CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - reinterpret_cast(certChain[0].c_str()), - static_cast(certChain[0].size()))); - if (cert == nullptr) + winhttp_cert_context cert; + cert.raw = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + reinterpret_cast(certChain[0].c_str()), + static_cast(certChain[0].size())); + if (cert.raw == nullptr) { return false; } // Let the OS build a certificate chain from the server certificate. - CERT_CHAIN_PARA params; - ZeroMemory(¶ms, sizeof(params)); - params.cbSize = sizeof(CERT_CHAIN_PARA); - params.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; - LPSTR usages[] = {(LPSTR)szOID_PKIX_KP_SERVER_AUTH, - - // For older servers and to match IE. - (LPSTR)szOID_SERVER_GATED_CRYPTO, - (LPSTR)szOID_SGC_NETSCAPE}; - params.RequestedUsage.Usage.cUsageIdentifier = std::extent::value; - params.RequestedUsage.Usage.rgpszUsageIdentifier = usages; - PCCERT_CHAIN_CONTEXT chainContext; - chain_context chain; - if (!CertGetCertificateChain( - nullptr, cert.get(), nullptr, nullptr, ¶ms, CERT_CHAIN_REVOCATION_CHECK_CHAIN, nullptr, &chainContext)) + char oidPkixKpServerAuth[] = szOID_PKIX_KP_SERVER_AUTH; + char oidServerGatedCrypto[] = szOID_SERVER_GATED_CRYPTO; + char oidSgcNetscape[] = szOID_SGC_NETSCAPE; + char* chainUses[] = { + oidPkixKpServerAuth, + oidServerGatedCrypto, + oidSgcNetscape, + }; + CERT_CHAIN_PARA chainPara = {sizeof(chainPara)}; + chainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; + chainPara.RequestedUsage.Usage.cUsageIdentifier = sizeof(chainUses) / sizeof(char*); + chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = chainUses; + + winhttp_cert_chain_context chainContext; + if (!CertGetCertificateChain(nullptr, + cert.raw, + nullptr, + cert.raw->hCertStore, + &chainPara, + CERT_CHAIN_REVOCATION_CHECK_CHAIN, + nullptr, + &chainContext.raw)) { return false; } - chain.reset(chainContext); // Check to see if the certificate chain is actually trusted. - if (chain->TrustStatus.dwErrorStatus != CERT_TRUST_NO_ERROR) + if (chainContext.raw->TrustStatus.dwErrorStatus != CERT_TRUST_NO_ERROR) + { + return false; + } + + auto u16HostName = utility::conversions::to_utf16string(hostname); + HTTPSPolicyCallbackData policyData = { + {sizeof(policyData)}, + AUTHTYPE_SERVER, + 0, + &u16HostName[0], + }; + CERT_CHAIN_POLICY_PARA policyPara = {sizeof(policyPara)}; + policyPara.pvExtraPolicyPara = &policyData; + CERT_CHAIN_POLICY_STATUS policyStatus = {sizeof(policyStatus)}; + if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext.raw, &policyPara, &policyStatus)) + { + return false; + } + + if (policyStatus.dwError) { return false; } diff --git a/Release/include/cpprest/details/x509_cert_utilities.h b/Release/src/http/common/x509_cert_utilities.h similarity index 51% rename from Release/include/cpprest/details/x509_cert_utilities.h rename to Release/src/http/common/x509_cert_utilities.h index cc40d9ccfb..e19af0498a 100644 --- a/Release/include/cpprest/details/x509_cert_utilities.h +++ b/Release/src/http/common/x509_cert_utilities.h @@ -13,9 +13,52 @@ #pragma once -#include +#if defined(_WIN32) +#include + +namespace web { namespace http { namespace client { namespace details { + +struct winhttp_cert_context +{ + PCCERT_CONTEXT raw; + winhttp_cert_context() noexcept : raw(nullptr) {} + winhttp_cert_context(const winhttp_cert_context&) = delete; + winhttp_cert_context& operator=(const winhttp_cert_context&) = delete; + ~winhttp_cert_context() + { + // https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-certfreecertificatecontext + // "The function always returns nonzero." + if (raw) + { + (void)CertFreeCertificateContext(raw); + } + } +}; + +struct winhttp_cert_chain_context +{ + PCCERT_CHAIN_CONTEXT raw; + winhttp_cert_chain_context() noexcept : raw(nullptr) {} + winhttp_cert_chain_context(const winhttp_cert_chain_context&) = delete; + winhttp_cert_chain_context& operator=(const winhttp_cert_chain_context&) = delete; + ~winhttp_cert_chain_context() + { + if (raw) + { + CertFreeCertificateChain(raw); + } + } +}; -#if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) || (defined(_WIN32) && !defined(__cplusplus_winrt) && !defined(_M_ARM) && !defined(CPPREST_EXCLUDE_WEBSOCKETS)) +}}}} // namespaces +#endif // _WIN32 + +#if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) || (defined(_WIN32) && !defined(__cplusplus_winrt) && !defined(_M_ARM) && !defined(CPPREST_EXCLUDE_WEBSOCKETS)) + #define CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE +#endif + +#ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE +#include #if defined(_MSC_VER) #pragma warning(push) @@ -37,7 +80,7 @@ namespace web { namespace http { namespace client { namespace details { /// /// Using platform specific APIs verifies server certificate. -/// Currently implemented to work on iOS, Android, and OS X. +/// Currently implemented to work on Windows, iOS, Android, and OS X. /// /// Boost.ASIO context to get certificate chain from. /// Host name from the URI. @@ -46,4 +89,4 @@ bool verify_cert_chain_platform_specific(boost::asio::ssl::verify_context &verif }}}} -#endif \ No newline at end of file +#endif // CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index c670dd0a61..39b7121d57 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -15,7 +15,7 @@ #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) -#include "cpprest/details/x509_cert_utilities.h" +#include "../../http/common/x509_cert_utilities.h" #include "pplx/threadpool.h" #include "ws_client_impl.h" @@ -122,7 +122,7 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: wspp_callback_client(websocket_client_config config) : websocket_client_callback_impl(std::move(config)), m_state(CREATED) -#if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) || defined(_WIN32) +#ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE , m_openssl_failed(false) #endif {} @@ -188,16 +188,16 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: sslContext->set_verify_mode(boost::asio::ssl::context::verify_none); } -#if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) || defined(_WIN32) +#ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE m_openssl_failed = false; #endif sslContext->set_verify_callback([this](bool preverified, boost::asio::ssl::verify_context &verifyCtx) { -#if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) || defined(_WIN32) - // On OS X, iOS, and Android, OpenSSL doesn't have access to where the OS - // stores keychains. If OpenSSL fails we will doing verification at the - // end using the whole certificate chain so wait until the 'leaf' cert. - // For now return true so OpenSSL continues down the certificate chain. +#ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE + // Attempt to use platform certificate validation when it is available: + // If OpenSSL fails we will doing verification at the end using the whole certificate chain, + // so wait until the 'leaf' cert. For now return true so OpenSSL continues down the certificate + // chain. if(!preverified) { m_openssl_failed = true; @@ -778,7 +778,7 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: // Used to track if any of the OpenSSL server certificate verifications // failed. This can safely be tracked at the client level since connections // only happen once for each client. -#if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) || defined(_WIN32) +#ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE bool m_openssl_failed; #endif diff --git a/Release/tests/functional/http/client/outside_tests.cpp b/Release/tests/functional/http/client/outside_tests.cpp index 00404a290f..f6ea1396cf 100644 --- a/Release/tests/functional/http/client/outside_tests.cpp +++ b/Release/tests/functional/http/client/outside_tests.cpp @@ -173,8 +173,8 @@ static void test_ignored_ssl_cert(const uri& base_uri) http_client_config config; config.set_validate_certificates(false); http_client client(base_uri, config); - auto request = client.request(methods::GET).get(); - VERIFY_ARE_EQUAL(status_codes::OK, request.status_code()); + auto response = client.request(methods::GET).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); }); } #endif // !defined(__cplusplus_winrt) @@ -197,10 +197,34 @@ TEST(server_hostname_mismatch) } #if !defined(__cplusplus_winrt) +TEST(server_hostname_host_override, + "Ignore:Android", "229", + "Ignore:Apple", "229", + "Ignore:Linux", "229") +{ + handle_timeout([] + { + http_client client(U("https://wrong.host.badssl.com/")); + http_request req(methods::GET); + req.headers().add(U("Host"), U("badssl.com")); + auto response = client.request(req).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + }); +} + TEST(server_hostname_mismatch_ignored) { test_ignored_ssl_cert(U("https://wrong.host.badssl.com/")); } + +TEST(server_hostname_host_override_after_upgrade) +{ + http_client client(U("http://198.35.26.96/")); + http_request req(methods::GET); + req.headers().add(U("Host"), U("en.wikipedia.org")); + auto response = client.request(req).get(); + VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); +} #endif // !defined(__cplusplus_winrt) TEST(server_cert_expired) @@ -215,7 +239,10 @@ TEST(server_cert_expired_ignored) } #endif // !defined(__cplusplus_winrt) -TEST(server_cert_revoked) +TEST(server_cert_revoked, + "Ignore:Android", "229", + "Ignore:Apple", "229", + "Ignore:Linux", "229") { test_failed_ssl_cert(U("https://revoked.badssl.com/")); } From b569ec3983b32b662b39a01afac3e0ea1fd3186d Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Sat, 11 Aug 2018 22:36:23 -0700 Subject: [PATCH 247/438] Avoid saying constexpr for VS2013. (#834) --- Release/include/cpprest/asyncrt_utils.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index 5978a2b051..b4b6c591f4 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -359,7 +359,13 @@ namespace details inline bool __cdecl is_alnum(const unsigned char uch) CPPREST_NOEXCEPT { // test if uch is an alnum character // special casing char to avoid branches - static constexpr bool is_alnum_table[UCHAR_MAX + 1] = + static + #if !defined(_MSC_VER) || _MSC_VER >= 1900 + constexpr + #else + const + #endif + bool is_alnum_table[UCHAR_MAX + 1] = { /* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */ /* 0X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, From 4e19c0cfb439febf6b3ee20efc857313ca2ba7f7 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Wed, 15 Aug 2018 12:22:20 -0700 Subject: [PATCH 248/438] Implement host override of CN checking in the ASIO backend (#832) * Implement host override of CN checking in the ASIO backend Add new function calc_cn_host which applies our host header override policy. Add the CN hostname used to asio_connection. Change the protocol such that the SSL upgrade request needs to come with the target hostname to use. Replace std::deque in connection pooling with a version that has constant amortized time per insertion. (std::deque is only constant amortized time for insertions in terms of element operations, not overall). Factor out the replacement policy from the overall pool machinery. Change release() to take shared_ptr&& to make sure the caller has let go. Enable verify_cert_chain_platform_specific on Windows; otherwise OpenSSL says that the root CAs are untrusted and all SSL tests fail on Windows. This accidentially repairs these test cases on Windows: **** outside_tests:outside_wikipedia_compressed_http_response FAILED **** **** outside_tests:multiple_https_requests FAILED **** **** outside_tests:outside_ssl_json FAILED **** * Add missing std::move. * Use hot connections instead of cold connections in connection pool. * Put timer start code back. * Reset the shared_ptr when it is being dropped. * Fix end comment broken by merge hell. --- Release/src/http/client/http_client_asio.cpp | 255 ++++++++++++------ Release/src/http/common/x509_cert_utilities.h | 62 +++-- .../functional/http/client/outside_tests.cpp | 10 +- 3 files changed, 221 insertions(+), 106 deletions(-) diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index d3002dfc09..e3ea15c9ff 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -81,7 +81,35 @@ using utility::conversions::details::to_string; using std::to_string; #endif -static const std::string CRLF("\r\n"); +namespace +{ +const std::string CRLF("\r\n"); + +std::string calc_cn_host(const bool secure, + const web::http::uri& baseUri, + const web::http::http_headers& requestHeaders) +{ + std::string result; + if (secure) + { + const utility::string_t* encResult; + const auto hostHeader = requestHeaders.find(_XPLATSTR("Host")); + if (hostHeader == requestHeaders.end()) + { + encResult = &baseUri.host(); + } + else + { + encResult = &hostHeader->second; + } + + result = utility::conversions::to_utf8string(*encResult); + utility::details::inplace_tolower(result); + } + + return result; +} +} // namespace namespace web { @@ -119,14 +147,21 @@ class asio_connection public: asio_connection(boost::asio::io_service& io_service) - : m_socket(io_service), m_is_reused(false), m_keep_alive(true), m_closed(false) + : m_socket_lock() + , m_socket(io_service) + , m_ssl_stream() + , m_cn_hostname() + , m_is_reused(false) + , m_keep_alive(true) + , m_closed(false) { } ~asio_connection() { close(); } // This simply instantiates the internal state to support ssl. It does not perform the handshake. - void upgrade_to_ssl(const std::function& ssl_context_callback) + void upgrade_to_ssl(std::string&& cn_hostname, + const std::function& ssl_context_callback) { std::lock_guard lock(m_socket_lock); assert(!is_ssl()); @@ -139,6 +174,7 @@ class asio_connection } m_ssl_stream = utility::details::make_unique>( m_socket, ssl_context); + m_cn_hostname = std::move(cn_hostname); } void close() @@ -166,6 +202,7 @@ class asio_connection void set_keep_alive(bool keep_alive) { m_keep_alive = keep_alive; } bool keep_alive() const { return m_keep_alive; } bool is_ssl() const { return m_ssl_stream ? true : false; } + const std::string& cn_hostname() const { return m_cn_hostname; } // Check if the error code indicates that the connection was closed by the // server: this is used to detect if a connection in the pool was closed during @@ -223,7 +260,6 @@ class asio_connection template void async_handshake(boost::asio::ssl::stream_base::handshake_type type, const http_client_config& config, - const std::string& host_name, const HandshakeHandler& handshake_handler, const CertificateHandler& cert_handler) { @@ -244,7 +280,7 @@ class asio_connection // Check to set host name for Server Name Indication (SNI) if (config.is_tlsext_sni_enabled()) { - SSL_set_tlsext_host_name(m_ssl_stream->native_handle(), const_cast(host_name.data())); + SSL_set_tlsext_host_name(m_ssl_stream->native_handle(), &m_cn_hostname[0]); } m_ssl_stream->async_handshake(type, handshake_handler); @@ -301,22 +337,60 @@ class asio_connection std::mutex m_socket_lock; tcp::socket m_socket; std::unique_ptr> m_ssl_stream; + std::string m_cn_hostname; bool m_is_reused; bool m_keep_alive; bool m_closed; }; +class connection_pool_stack +{ +public: + // attempts to acquire a connection from the deque; returns nullptr if no connection is + // available + std::shared_ptr try_acquire() CPPREST_NOEXCEPT + { + const size_t oldConnectionsSize = m_connections.size(); + if (m_highWater > oldConnectionsSize) + { + m_highWater = oldConnectionsSize; + } + + if (oldConnectionsSize == 0) + { + return nullptr; + } + + auto result = std::move(m_connections.back()); + m_connections.pop_back(); + return result; + } + + // releases `released` back to the connection pool + void release(std::shared_ptr&& released) + { + m_connections.push_back(std::move(released)); + } + + bool free_stale_connections() CPPREST_NOEXCEPT + { + m_connections.erase(m_connections.begin(), m_connections.begin() + m_highWater); + const size_t connectionsSize = m_connections.size(); + m_highWater = connectionsSize; + return (connectionsSize != 0); + } + +private: + size_t m_highWater = 0; + std::vector> m_connections; +}; + /// Implements a connection pool with adaptive connection removal /// -/// The timeout mechanism is based on the `uint64_t m_epoch` member. Every 30 seconds, -/// the lambda in `start_epoch_interval` fires, triggering the cleanup of any -/// connections that have resided in the pool since the last cleanup phase's epoch. -/// -/// This works because the `m_connections` member functions is used in LIFO order. -/// LIFO usage guarantees that the elements remain sorted based on epoch number, -/// since the highest epoch is always removed and on insertion the next monotonically -/// increasing epoch is used. +/// Every 30 seconds, the lambda in `start_epoch_interval` fires, triggering the +/// cleanup of any connections that have resided in the pool since the last +/// cleanup phase. /// /// During the cleanup phase, connections are removed starting with the oldest. This /// ensures that if a high intensity workload is followed by a low intensity workload, @@ -327,93 +401,107 @@ class asio_connection /// /// while(1) /// { -/// auto conn = pool.acquire(); +/// auto conn = pool.try_acquire(); /// if (!conn) conn = new_conn(); -/// pool.release(conn); +/// pool.release(std::move(conn)); /// } /// /// class asio_connection_pool final : public std::enable_shared_from_this { public: - asio_connection_pool() : m_pool_epoch_timer(crossplat::threadpool::shared_instance().service()) {} + asio_connection_pool() + : m_lock() + , m_connections() + , m_is_timer_running(false) + , m_pool_epoch_timer(crossplat::threadpool::shared_instance().service()) + { + } - std::shared_ptr acquire() + asio_connection_pool(const asio_connection_pool&) = delete; + asio_connection_pool& operator=(const asio_connection_pool&) = delete; + + std::shared_ptr try_acquire(const std::string& cn_hostname) { std::lock_guard lock(m_lock); + if (m_connections.empty()) + { + return nullptr; + } - if (m_connections.empty()) return nullptr; + auto conn = m_connections[cn_hostname].try_acquire(); + if (conn) + { + conn->start_reuse(); + } - auto conn = std::move(m_connections.back().second); - m_connections.pop_back(); - conn->start_reuse(); return conn; } - void release(const std::shared_ptr& connection) + void release(std::shared_ptr&& connection) { connection->cancel(); - - if (!connection->keep_alive()) return; + if (!connection->keep_alive()) + { + connection.reset(); + return; + } std::lock_guard lock(m_lock); - if (!is_timer_running) + if (!m_is_timer_running) { start_epoch_interval(shared_from_this()); - is_timer_running = true; + m_is_timer_running = true; } - m_epoch++; - m_connections.emplace_back(m_epoch, std::move(connection)); + m_connections[connection->cn_hostname()].release(std::move(connection)); } private: // Note: must be called under m_lock static void start_epoch_interval(const std::shared_ptr& pool) { - _ASSERTE(pool.get() != nullptr); - auto& self = *pool; std::weak_ptr weak_pool = pool; - self.m_prev_epoch = self.m_epoch; - pool->m_pool_epoch_timer.expires_from_now(boost::posix_time::seconds(30)); - pool->m_pool_epoch_timer.async_wait([weak_pool](const boost::system::error_code& ec) { - if (ec) return; + self.m_pool_epoch_timer.expires_from_now(boost::posix_time::seconds(30)); + self.m_pool_epoch_timer.async_wait([weak_pool](const boost::system::error_code& ec) { + if (ec) + { + return; + } auto pool = weak_pool.lock(); - if (!pool) return; - auto& self = *pool; - auto& connections = self.m_connections; + if (!pool) + { + return; + } + auto& self = *pool; std::lock_guard lock(self.m_lock); - if (self.m_prev_epoch == self.m_epoch) + bool restartTimer = false; + for (auto& entry : self.m_connections) { - connections.clear(); - self.is_timer_running = false; - return; + if (entry.second.free_stale_connections()) + { + restartTimer = true; + } } - else + + if (restartTimer) { - auto prev_epoch = self.m_prev_epoch; - auto erase_end = std::find_if(connections.begin(), - connections.end(), - [prev_epoch](std::pair>& p) { - return p.first > prev_epoch; - }); - - connections.erase(connections.begin(), erase_end); start_epoch_interval(pool); } + else + { + self.m_is_timer_running = false; + } }); } std::mutex m_lock; - std::deque>> m_connections; - - uint64_t m_epoch = 0; - uint64_t m_prev_epoch = 0; - bool is_timer_running = false; + std::map m_connections; + bool m_is_timer_running; boost::asio::deadline_timer m_pool_epoch_timer; }; @@ -430,16 +518,20 @@ class asio_client final : public _http_client_communicator virtual void send_request(const std::shared_ptr& request_ctx) override; - void release_connection(std::shared_ptr& conn) { m_pool->release(conn); } - std::shared_ptr obtain_connection() - { - std::shared_ptr conn = m_pool->acquire(); + void release_connection(std::shared_ptr&& conn) { m_pool->release(std::move(conn)); } + std::shared_ptr obtain_connection(const http_request& req) + { + std::string cn_host = calc_cn_host(m_start_with_ssl, base_uri(), req.headers()); + std::shared_ptr conn = m_pool->try_acquire(cn_host); if (conn == nullptr) { // Pool was empty. Create a new connection conn = std::make_shared(crossplat::threadpool::shared_instance().service()); - if (m_start_with_ssl) conn->upgrade_to_ssl(this->client_config().get_ssl_context_callback()); + if (m_start_with_ssl) + { + conn->upgrade_to_ssl(std::move(cn_host), this->client_config().get_ssl_context_callback()); + } } return conn; @@ -447,7 +539,8 @@ class asio_client final : public _http_client_communicator virtual pplx::task propagate(http_request request) override; -public: + bool start_with_ssl() const CPPREST_NOEXCEPT { return m_start_with_ssl; } + tcp::resolver m_resolver; private: @@ -470,7 +563,7 @@ class asio_context final : public request_context, public std::enable_shared_fro , m_connection(connection) #ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE , m_openssl_failed(false) -#endif +#endif // CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE { } @@ -478,14 +571,14 @@ class asio_context final : public request_context, public std::enable_shared_fro { m_timer.stop(); // Release connection back to the pool. If connection was not closed, it will be put to the pool for reuse. - std::static_pointer_cast(m_http_client)->release_connection(m_connection); + std::static_pointer_cast(m_http_client)->release_connection(std::move(m_connection)); } static std::shared_ptr create_request_context(std::shared_ptr<_http_client_communicator>& client, http_request& request) { auto client_cast(std::static_pointer_cast(client)); - auto connection(client_cast->obtain_connection()); + auto connection(client_cast->obtain_connection(request)); auto ctx = std::make_shared(client, request, connection); ctx->m_timer.set_ctx(std::weak_ptr(ctx)); return ctx; @@ -578,7 +671,7 @@ class asio_context final : public request_context, public std::enable_shared_fro m_context->m_timer.reset(); //// Replace the connection. This causes old connection object to go out of scope. auto client = std::static_pointer_cast(m_context->m_http_client); - m_context->m_connection = client->obtain_connection(); + m_context->m_connection = client->obtain_connection(m_context->m_request); auto endpoint = *endpoints; m_context->m_connection->async_connect(endpoint, @@ -869,7 +962,12 @@ class asio_context final : public request_context, public std::enable_shared_fro } private: - void upgrade_to_ssl() { m_connection->upgrade_to_ssl(m_http_client->client_config().get_ssl_context_callback()); } + void upgrade_to_ssl() + { + auto& client = static_cast(*m_http_client); + m_connection->upgrade_to_ssl(calc_cn_host(client.start_with_ssl(), client.base_uri(), m_request.headers()), + client.client_config().get_ssl_context_callback()); + } std::string generate_basic_auth_header() { @@ -951,7 +1049,7 @@ class asio_context final : public request_context, public std::enable_shared_fro { // Replace the connection. This causes old connection object to go out of scope. auto client = std::static_pointer_cast(m_http_client); - m_connection = client->obtain_connection(); + m_connection = client->obtain_connection(m_request); auto endpoint = *endpoints; m_connection->async_connect( @@ -987,11 +1085,11 @@ class asio_context final : public request_context, public std::enable_shared_fro m_connection->async_handshake( boost::asio::ssl::stream_base::client, m_http_client->client_config(), - utility::conversions::to_utf8string(m_http_client->base_uri().host()), boost::bind(&asio_context::handle_handshake, shared_from_this(), boost::asio::placeholders::error), - // Use a weak_ptr since the verify_callback is stored until the connection is destroyed. - // This avoids creating a circular reference since we pool connection objects. + // Use a weak_ptr since the verify_callback is stored until the connection is + // destroyed. This avoids creating a circular reference since we pool connection + // objects. [weakCtx](bool preverified, boost::asio::ssl::verify_context& verify_context) { auto this_request = weakCtx.lock(); if (this_request) @@ -1031,23 +1129,22 @@ class asio_context final : public request_context, public std::enable_shared_fro // certificate chain, the rest are optional intermediate certificates, followed // finally by the root CA self signed certificate. - const auto& host = utility::conversions::to_utf8string(m_http_client->base_uri().host()); #ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE - // Attempt to use platform certificate validation when it is available: - // If OpenSSL fails we will doing verification at the end using the whole certificate chain, - // so wait until the 'leaf' cert. For now return true so OpenSSL continues down the certificate - // chain. + // If OpenSSL fails we will doing verification at the end using the whole certificate + // chain so wait until the 'leaf' cert. For now return true so OpenSSL continues down + // the certificate chain. if (!preverified) { m_openssl_failed = true; } + if (m_openssl_failed) { - return verify_cert_chain_platform_specific(verifyCtx, host); + return verify_cert_chain_platform_specific(verifyCtx, m_connection->cn_hostname()); } -#endif +#endif // CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE - boost::asio::ssl::rfc2818_verification rfc2818(host); + boost::asio::ssl::rfc2818_verification rfc2818(m_connection->cn_hostname()); return rfc2818(preverified, verifyCtx); } @@ -1759,7 +1856,7 @@ class asio_context final : public request_context, public std::enable_shared_fro #ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE bool m_openssl_failed; -#endif +#endif // CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE }; std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage(uri&& base_uri, diff --git a/Release/src/http/common/x509_cert_utilities.h b/Release/src/http/common/x509_cert_utilities.h index e19af0498a..581a5189c4 100644 --- a/Release/src/http/common/x509_cert_utilities.h +++ b/Release/src/http/common/x509_cert_utilities.h @@ -1,23 +1,29 @@ /*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Contains utility functions for helping to verify server certificates in OS X/iOS and Android. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * Contains utility functions for helping to verify server certificates in OS X/iOS and Android. + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ #pragma once #if defined(_WIN32) #include -namespace web { namespace http { namespace client { namespace details { - +namespace web +{ +namespace http +{ +namespace client +{ +namespace details +{ struct winhttp_cert_context { PCCERT_CONTEXT raw; @@ -49,12 +55,16 @@ struct winhttp_cert_chain_context } } }; - -}}}} // namespaces +} +} +} +} // namespaces #endif // _WIN32 -#if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) || (defined(_WIN32) && !defined(__cplusplus_winrt) && !defined(_M_ARM) && !defined(CPPREST_EXCLUDE_WEBSOCKETS)) - #define CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE +#if defined(__APPLE__) || (defined(ANDROID) || defined(__ANDROID__)) || \ + (defined(_WIN32) && defined(CPPREST_FORCE_HTTP_CLIENT_ASIO)) || \ + (defined(_WIN32) && !defined(__cplusplus_winrt) && !defined(_M_ARM) && !defined(CPPREST_EXCLUDE_WEBSOCKETS)) +#define CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE #endif #ifdef CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE @@ -76,8 +86,14 @@ struct winhttp_cert_chain_context #pragma warning(pop) #endif -namespace web { namespace http { namespace client { namespace details { - +namespace web +{ +namespace http +{ +namespace client +{ +namespace details +{ /// /// Using platform specific APIs verifies server certificate. /// Currently implemented to work on Windows, iOS, Android, and OS X. @@ -85,8 +101,10 @@ namespace web { namespace http { namespace client { namespace details { /// Boost.ASIO context to get certificate chain from. /// Host name from the URI. /// True if verification passed and server can be trusted, false otherwise. -bool verify_cert_chain_platform_specific(boost::asio::ssl::verify_context &verifyCtx, const std::string &hostName); - -}}}} +bool verify_cert_chain_platform_specific(boost::asio::ssl::verify_context& verifyCtx, const std::string& hostName); +} +} +} +} #endif // CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE diff --git a/Release/tests/functional/http/client/outside_tests.cpp b/Release/tests/functional/http/client/outside_tests.cpp index f6ea1396cf..7c0438d48c 100644 --- a/Release/tests/functional/http/client/outside_tests.cpp +++ b/Release/tests/functional/http/client/outside_tests.cpp @@ -197,10 +197,7 @@ TEST(server_hostname_mismatch) } #if !defined(__cplusplus_winrt) -TEST(server_hostname_host_override, - "Ignore:Android", "229", - "Ignore:Apple", "229", - "Ignore:Linux", "229") +TEST(server_hostname_host_override) { handle_timeout([] { @@ -223,7 +220,10 @@ TEST(server_hostname_host_override_after_upgrade) http_request req(methods::GET); req.headers().add(U("Host"), U("en.wikipedia.org")); auto response = client.request(req).get(); - VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); + // WinHTTP will transparently follow the HTTP 301 upgrade request redirect, + // ASIO does not and will return the 301 directly. + const auto statusCode = response.status_code(); + CHECK(statusCode == status_codes::OK || statusCode == status_codes::MovedPermanently); } #endif // !defined(__cplusplus_winrt) From 29e23c253b63bd753923c3822fc9051a67399fc3 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 15 Aug 2018 12:40:46 -0700 Subject: [PATCH 249/438] Mint version 2.10.4 --- Build/version.props | 2 +- Release/CMakeLists.txt | 2 +- Release/include/cpprest/version.h | 2 +- changelog.md | 12 ++++++++++++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Build/version.props b/Build/version.props index 983ce9e3c5..8f840c5f3d 100644 --- a/Build/version.props +++ b/Build/version.props @@ -4,7 +4,7 @@ cpprest 2 10 - 3 + 4 $(CppRestSDKVersionMajor)_$(CppRestSDKVersionMinor) $(CppRestSDKVersionMajor).$(CppRestSDKVersionMinor) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index a79a4ffbbc..c93d3cc498 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -11,7 +11,7 @@ endif() set(CPPREST_VERSION_MAJOR 2) set(CPPREST_VERSION_MINOR 10) -set(CPPREST_VERSION_REVISION 3) +set(CPPREST_VERSION_REVISION 4) enable_testing() diff --git a/Release/include/cpprest/version.h b/Release/include/cpprest/version.h index a4cf42cb5b..3167e148b0 100644 --- a/Release/include/cpprest/version.h +++ b/Release/include/cpprest/version.h @@ -5,7 +5,7 @@ */ #define CPPREST_VERSION_REVISION 2 #define CPPREST_VERSION_MINOR 10 -#define CPPREST_VERSION_MAJOR 3 +#define CPPREST_VERSION_MAJOR 4 #define CPPREST_VERSION (CPPREST_VERSION_MAJOR*100000+CPPREST_VERSION_MINOR*100+CPPREST_VERSION_REVISION) diff --git a/changelog.md b/changelog.md index 047ca874f3..b37c24792e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,15 @@ +cpprestsdk (2.10.4) +---------------------- +* Added a `.clang-format` to enable consistent formatting. +* Added support for `Host:` headers changing the checked CNAME field for SSL certificates in WinHTTP and Asio. +* PR#736 passes 0666 to open() for creating files to better match the default behavior for other http clients (wget, etc). +* PR#732 fixes a build issue with clang +* PR#737 taught our cmake to respect the GNUInstallDirs variables +* PR#762 improved handling of dead connections in the connection pool on Asio. +* PR#750 improved error handling in the accept() call in `http_listener` +* PR#776 improved the iOS buildsystem +-- cpprestsdk team WED, 15 Aug 2018 12:35:00 -0800 + cpprestsdk (2.10.3) ---------------------- * Added a root `CMakeLists.txt` to improve support for VS2017 Open Folder. From 25d6b26f7038eeec3b51e2e0a70960a8e34fcd68 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Fri, 17 Aug 2018 09:48:34 -0700 Subject: [PATCH 250/438] Fix incorrect version.h. Fixes #942 --- Release/include/cpprest/version.h | 4 ++-- changelog.md | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Release/include/cpprest/version.h b/Release/include/cpprest/version.h index 3167e148b0..df0f99cf45 100644 --- a/Release/include/cpprest/version.h +++ b/Release/include/cpprest/version.h @@ -3,9 +3,9 @@ * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. * */ -#define CPPREST_VERSION_REVISION 2 +#define CPPREST_VERSION_REVISION 5 #define CPPREST_VERSION_MINOR 10 -#define CPPREST_VERSION_MAJOR 4 +#define CPPREST_VERSION_MAJOR 2 #define CPPREST_VERSION (CPPREST_VERSION_MAJOR*100000+CPPREST_VERSION_MINOR*100+CPPREST_VERSION_REVISION) diff --git a/changelog.md b/changelog.md index b37c24792e..569401e517 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,8 @@ +cpprestsdk (2.10.5) +---------------------- +* Issue#842 Fix incorrect `cpprest/version.h` +-- cpprestsdk team FRI, 17 Aug 2018 09:47:00 -0800 + cpprestsdk (2.10.4) ---------------------- * Added a `.clang-format` to enable consistent formatting. From f9f518e4ad84577eb684ad8235181e4495299af4 Mon Sep 17 00:00:00 2001 From: Gianfranco Costamagna Date: Mon, 20 Aug 2018 19:27:01 +0200 Subject: [PATCH 251/438] Fix another clang build failure (Fixes: #747) (#844) * Fix another clang build failure (Fixes: #747) ===> Building for cpprestsdk-2.9.1_5 [1/161] /usr/local/libexec/ccache/c++ -Dcpprest_EXPORTS -Iinclude -isystem /usr/local/include -isystem libs/websocketpp -Isrc/../include -Isrc/pch -O2 -pipe -fstack-protector -fno-strict-aliasing -stdlib=libc++ -Wno-return-type-c-linkage -Wno-unneeded-internal-declaration -std=c++11 -fno-strict-aliasing -O2 -pipe -fstack-protector -fno-strict-aliasing -fPIC -Wall -Wextra -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls -Wno-overloaded-virtual -Wno-sign-conversion -Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-char-subscripts -Wno-switch -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated -Wno-unused-value -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-unused-function -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-reorder -Wno-unused-local-typedefs -Werror -pedantic -MD -MT src/CMakeFiles/cpprest.dir/pplx/pplx.cpp.o -MF src/CMakeFiles/cpprest.dir/pplx/pplx.cpp.o.d -o src/CMakeFiles/cpprest.dir/pplx/pplx.cpp.o -c src/pplx/pplx.cpp FAILED: src/CMakeFiles/cpprest.dir/pplx/pplx.cpp.o /usr/local/libexec/ccache/c++ -Dcpprest_EXPORTS -Iinclude -isystem /usr/local/include -isystem libs/websocketpp -Isrc/../include -Isrc/pch -O2 -pipe -fstack-protector -fno-strict-aliasing -stdlib=libc++ -Wno-return-type-c-linkage -Wno-unneeded-internal-declaration -std=c++11 -fno-strict-aliasing -O2 -pipe -fstack-protector -fno-strict-aliasing -fPIC -Wall -Wextra -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls -Wno-overloaded-virtual -Wno-sign-conversion -Wno-deprecated -Wno-unknown-pragmas -Wno-reorder -Wno-char-subscripts -Wno-switch -Wno-unused-parameter -Wno-unused-variable -Wno-deprecated -Wno-unused-value -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-unused-function -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-reorder -Wno-unused-local-typedefs -Werror -pedantic -MD -MT src/CMakeFiles/cpprest.dir/pplx/pplx.cpp.o -MF src/CMakeFiles/cpprest.dir/pplx/pplx.cpp.o.d -o src/CMakeFiles/cpprest.dir/pplx/pplx.cpp.o -c src/pplx/pplx.cpp In file included from src/pplx/pplx.cpp:14: In file included from src/pch/stdafx.h:23: In file included from include/cpprest/details/basic_types.h:16: In file included from /usr/include/c++/v1/string:477: In file included from /usr/include/c++/v1/string_view:176: In file included from /usr/include/c++/v1/__string:56: In file included from /usr/include/c++/v1/algorithm:643: /usr/include/c++/v1/memory:3656:5: error: destructor called on non-final 'pplx::details::linux_scheduler' that has virtual functions but non-virtual destructor [-Werror,-Wdelete-non-virtual-dtor] __data_.second().~_Tp(); ^ /usr/include/c++/v1/memory:3612:5: note: in instantiation of member function 'std::__1::__shared_ptr_emplace >::__on_zero_shared' requested here __shared_ptr_emplace(_Alloc __a) ^ /usr/include/c++/v1/memory:4277:26: note: in instantiation of member function 'std::__1::__shared_ptr_emplace >::__shared_ptr_emplace' requested here ::new(__hold2.get()) _CntrlBlk(__a2, _VSTD::forward<_Args>(__args)...); ^ /usr/include/c++/v1/memory:4656:29: note: in instantiation of function template specialization 'std::__1::shared_ptr::make_shared<>' requested here return shared_ptr<_Tp>::make_shared(_VSTD::forward<_Args>(__args)...); ^ src/pplx/pplx.cpp:94:40: note: in instantiation of function template specialization 'std::__1::make_shared' requested here m_scheduler = std::make_shared< ::pplx::default_scheduler_t>(); ^ /usr/include/c++/v1/memory:3656:23: note: qualify call to silence this warning __data_.second().~_Tp(); ^ 1 error generated. * Fix apple build, by defining apple_scheduler there. --- Release/include/pplx/pplxlinux.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Release/include/pplx/pplxlinux.h b/Release/include/pplx/pplxlinux.h index 6aa1ba352e..78b6e1801a 100644 --- a/Release/include/pplx/pplxlinux.h +++ b/Release/include/pplx/pplxlinux.h @@ -240,6 +240,11 @@ namespace platform { public: _PPLXIMP virtual void schedule( TaskProc_t proc, _In_ void* param); +#if defined(__APPLE__) + virtual ~apple_scheduler() {} +#else + virtual ~linux_scheduler() {} +#endif }; } // namespace details From 66e50f02dde92f802bbd3a8d79c6352954665b9b Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Mon, 20 Aug 2018 16:52:11 -0700 Subject: [PATCH 252/438] Fix compiler errors and mint v2.10.6 --- Build/version.props | 2 +- Release/CMakeLists.txt | 2 +- Release/include/cpprest/asyncrt_utils.h | 8 +------- Release/include/cpprest/details/cpprest_compat.h | 3 +++ Release/include/cpprest/version.h | 2 +- Release/src/http/client/http_client_winhttp.cpp | 2 +- Release/src/http/common/x509_cert_utilities.h | 4 ++-- Release/src/utilities/asyncrt_utils.cpp | 8 ++++---- changelog.md | 5 +++++ 9 files changed, 19 insertions(+), 17 deletions(-) diff --git a/Build/version.props b/Build/version.props index 8f840c5f3d..2b67f6647e 100644 --- a/Build/version.props +++ b/Build/version.props @@ -4,7 +4,7 @@ cpprest 2 10 - 4 + 6 $(CppRestSDKVersionMajor)_$(CppRestSDKVersionMinor) $(CppRestSDKVersionMajor).$(CppRestSDKVersionMinor) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index c93d3cc498..3b99b85309 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -11,7 +11,7 @@ endif() set(CPPREST_VERSION_MAJOR 2) set(CPPREST_VERSION_MINOR 10) -set(CPPREST_VERSION_REVISION 4) +set(CPPREST_VERSION_REVISION 6) enable_testing() diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index b4b6c591f4..21c92de294 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -359,13 +359,7 @@ namespace details inline bool __cdecl is_alnum(const unsigned char uch) CPPREST_NOEXCEPT { // test if uch is an alnum character // special casing char to avoid branches - static - #if !defined(_MSC_VER) || _MSC_VER >= 1900 - constexpr - #else - const - #endif - bool is_alnum_table[UCHAR_MAX + 1] = + static CPPREST_CONSTEXPR bool is_alnum_table[UCHAR_MAX + 1] = { /* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */ /* 0X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/Release/include/cpprest/details/cpprest_compat.h b/Release/include/cpprest/details/cpprest_compat.h index 7b4f3c1842..1c48552eff 100644 --- a/Release/include/cpprest/details/cpprest_compat.h +++ b/Release/include/cpprest/details/cpprest_compat.h @@ -18,8 +18,10 @@ #if _MSC_VER >= 1900 #define CPPREST_NOEXCEPT noexcept +#define CPPREST_CONSTEXPR constexpr #else #define CPPREST_NOEXCEPT +#define CPPREST_CONSTEXPR const #endif #define CASABLANCA_UNREFERENCED_PARAMETER(x) (x) @@ -36,6 +38,7 @@ #define __assume(x) do { if (!(x)) __builtin_unreachable(); } while (false) #define CASABLANCA_UNREFERENCED_PARAMETER(x) (void)x #define CPPREST_NOEXCEPT noexcept +#define CPPREST_CONSTEXPR constexpr #include #define _ASSERTE(x) assert(x) diff --git a/Release/include/cpprest/version.h b/Release/include/cpprest/version.h index df0f99cf45..cb47ab9d05 100644 --- a/Release/include/cpprest/version.h +++ b/Release/include/cpprest/version.h @@ -3,7 +3,7 @@ * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. * */ -#define CPPREST_VERSION_REVISION 5 +#define CPPREST_VERSION_REVISION 6 #define CPPREST_VERSION_MINOR 10 #define CPPREST_VERSION_MAJOR 2 diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 83a60d6ce5..a1f69ab215 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -33,7 +33,7 @@ struct security_failure_message const char * text; }; -constexpr security_failure_message g_security_failure_messages[] = { +CPPREST_CONSTEXPR security_failure_message g_security_failure_messages[] = { { WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED, "WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED failed to check revocation status."}, { WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT, diff --git a/Release/src/http/common/x509_cert_utilities.h b/Release/src/http/common/x509_cert_utilities.h index 581a5189c4..9884b05993 100644 --- a/Release/src/http/common/x509_cert_utilities.h +++ b/Release/src/http/common/x509_cert_utilities.h @@ -27,7 +27,7 @@ namespace details struct winhttp_cert_context { PCCERT_CONTEXT raw; - winhttp_cert_context() noexcept : raw(nullptr) {} + winhttp_cert_context() CPPREST_NOEXCEPT : raw(nullptr) {} winhttp_cert_context(const winhttp_cert_context&) = delete; winhttp_cert_context& operator=(const winhttp_cert_context&) = delete; ~winhttp_cert_context() @@ -44,7 +44,7 @@ struct winhttp_cert_context struct winhttp_cert_chain_context { PCCERT_CHAIN_CONTEXT raw; - winhttp_cert_chain_context() noexcept : raw(nullptr) {} + winhttp_cert_chain_context() CPPREST_NOEXCEPT : raw(nullptr) {} winhttp_cert_chain_context(const winhttp_cert_chain_context&) = delete; winhttp_cert_chain_context& operator=(const winhttp_cert_chain_context&) = delete; ~winhttp_cert_chain_context() diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index 72f12ccf10..3faffd1e40 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -51,7 +51,7 @@ namespace } }; - constexpr to_lower_ch_impl to_lower_ch{}; + CPPREST_CONSTEXPR to_lower_ch_impl to_lower_ch{}; struct eq_lower_ch_impl { @@ -62,7 +62,7 @@ namespace } }; - constexpr eq_lower_ch_impl eq_lower_ch{}; + CPPREST_CONSTEXPR eq_lower_ch_impl eq_lower_ch{}; struct lt_lower_ch_impl { @@ -73,8 +73,8 @@ namespace } }; - constexpr lt_lower_ch_impl lt_lower_ch{}; -} + CPPREST_CONSTEXPR lt_lower_ch_impl lt_lower_ch{}; + } namespace utility { diff --git a/changelog.md b/changelog.md index 569401e517..dd190b70a9 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,8 @@ +cpprestsdk (2.10.6) +---------------------- +* PR#844 Fix clang build error +-- cpprestsdk team MON, 30 Aug 2018 16:51:00 -0800 + cpprestsdk (2.10.5) ---------------------- * Issue#842 Fix incorrect `cpprest/version.h` From cdc2948614df5e034f8b0f2e64e52c140404f670 Mon Sep 17 00:00:00 2001 From: Ernie Pistor Date: Wed, 12 Sep 2018 10:50:15 -0400 Subject: [PATCH 253/438] Add Transfer-Encoding compression/decompression support and extensible compress/decompress API --- Release/CMakeLists.txt | 2 + Release/cmake/cpprest_find_brotli.cmake | 10 + Release/cmake/cpprestsdk-config.in.cmake | 4 + Release/include/cpprest/asyncrt_utils.h | 2 +- .../include/cpprest/details/http_helpers.h | 66 - Release/include/cpprest/http_client.h | 12 +- Release/include/cpprest/http_compression.h | 329 ++++ Release/include/cpprest/http_msg.h | 156 ++ Release/src/CMakeLists.txt | 12 + Release/src/http/client/http_client.cpp | 65 +- Release/src/http/client/http_client_asio.cpp | 76 +- Release/src/http/client/http_client_impl.h | 6 +- .../src/http/client/http_client_winhttp.cpp | 813 +++++++++- Release/src/http/common/http_compression.cpp | 1110 +++++++++++++ Release/src/http/common/http_helpers.cpp | 325 ---- Release/src/http/common/http_msg.cpp | 80 +- .../src/http/listener/http_server_httpsys.cpp | 298 +++- .../src/http/listener/http_server_httpsys.h | 7 + .../functional/http/client/CMakeLists.txt | 1 + .../http/client/compression_tests.cpp | 1401 +++++++++++++++++ .../functional/http/client/outside_tests.cpp | 2 +- .../http/client/request_helper_tests.cpp | 62 +- .../http/utilities/include/test_http_server.h | 56 +- .../http/utilities/test_http_server.cpp | 4 +- 24 files changed, 4286 insertions(+), 613 deletions(-) create mode 100644 Release/cmake/cpprest_find_brotli.cmake create mode 100644 Release/include/cpprest/http_compression.h create mode 100644 Release/src/http/common/http_compression.cpp create mode 100644 Release/tests/functional/http/client/compression_tests.cpp diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 3b99b85309..18ece49310 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -18,6 +18,7 @@ enable_testing() set(WERROR ON CACHE BOOL "Treat Warnings as Errors.") set(CPPREST_EXCLUDE_WEBSOCKETS OFF CACHE BOOL "Exclude websockets functionality.") set(CPPREST_EXCLUDE_COMPRESSION OFF CACHE BOOL "Exclude compression functionality.") +set(CPPREST_EXCLUDE_BROTLI ON CACHE BOOL "Exclude Brotli compression functionality.") set(CPPREST_EXPORT_DIR lib/cpprestsdk CACHE STRING "Directory to install CMake config files.") set(CPPREST_INSTALL_HEADERS ON CACHE BOOL "Install header files.") set(CPPREST_INSTALL ON CACHE BOOL "Add install commands.") @@ -62,6 +63,7 @@ include(cmake/cpprest_find_boost.cmake) include(cmake/cpprest_find_zlib.cmake) include(cmake/cpprest_find_openssl.cmake) include(cmake/cpprest_find_websocketpp.cmake) +include(cmake/cpprest_find_brotli.cmake) include(CheckIncludeFiles) include(GNUInstallDirs) diff --git a/Release/cmake/cpprest_find_brotli.cmake b/Release/cmake/cpprest_find_brotli.cmake new file mode 100644 index 0000000000..7366100939 --- /dev/null +++ b/Release/cmake/cpprest_find_brotli.cmake @@ -0,0 +1,10 @@ +function(cpprest_find_brotli) + if(TARGET cpprestsdk_brotli_internal) + return() + endif() + + find_package(UNOFFICIAL-BROTLI REQUIRED) + + add_library(cpprestsdk_brotli_internal INTERFACE) + target_link_libraries(cpprestsdk_brotli_internal INTERFACE unofficial::brotli::brotlienc unofficial::brotli::brotlidec unofficial::brotli::brotlicommon) +endfunction() diff --git a/Release/cmake/cpprestsdk-config.in.cmake b/Release/cmake/cpprestsdk-config.in.cmake index 522f8f7db1..a00caa2f95 100644 --- a/Release/cmake/cpprestsdk-config.in.cmake +++ b/Release/cmake/cpprestsdk-config.in.cmake @@ -3,6 +3,10 @@ if(@CPPREST_USES_ZLIB@) find_dependency(ZLIB) endif() +if(@CPPREST_USES_BROTLI@) + find_dependency(UNOFFICIAL-BROTLI) +endif() + if(@CPPREST_USES_OPENSSL@) find_dependency(OpenSSL) endif() diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index 21c92de294..2739a13e35 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -503,7 +503,7 @@ _ASYNCRTIMP const std::error_category & __cdecl linux_category(); /// /// Gets the one global instance of the current platform's error category. -/// +/// _ASYNCRTIMP const std::error_category & __cdecl platform_category(); /// diff --git a/Release/include/cpprest/details/http_helpers.h b/Release/include/cpprest/details/http_helpers.h index 596ac9efaa..ad01e2eb67 100644 --- a/Release/include/cpprest/details/http_helpers.h +++ b/Release/include/cpprest/details/http_helpers.h @@ -41,70 +41,4 @@ namespace details _ASYNCRTIMP size_t __cdecl add_chunked_delimiters(_Out_writes_(buffer_size) uint8_t *data, _In_ size_t buffer_size, size_t bytes_read); } - namespace compression - { - enum class compression_algorithm : int - { - deflate = 15, - gzip = 31, - invalid = 9999 - }; - - using data_buffer = std::vector; - - class stream_decompressor - { - public: - - static compression_algorithm to_compression_algorithm(const utility::string_t& alg) - { - if (_XPLATSTR("gzip") == alg) - { - return compression_algorithm::gzip; - } - else if (_XPLATSTR("deflate") == alg) - { - return compression_algorithm::deflate; - } - - return compression_algorithm::invalid; - } - - static utility::string_t known_algorithms() { return _XPLATSTR("deflate, gzip"); } - - _ASYNCRTIMP static bool __cdecl is_supported(); - - _ASYNCRTIMP stream_decompressor(compression_algorithm alg); - - _ASYNCRTIMP data_buffer decompress(const data_buffer& input); - - _ASYNCRTIMP data_buffer decompress(const uint8_t* input, size_t input_size); - - _ASYNCRTIMP bool has_error() const; - - private: - class stream_decompressor_impl; - std::shared_ptr m_pimpl; - }; - - class stream_compressor - { - public: - - _ASYNCRTIMP static bool __cdecl is_supported(); - - _ASYNCRTIMP stream_compressor(compression_algorithm alg); - - _ASYNCRTIMP data_buffer compress(const data_buffer& input, bool finish); - - _ASYNCRTIMP data_buffer compress(const uint8_t* input, size_t input_size, bool finish); - - _ASYNCRTIMP bool has_error() const; - - private: - class stream_compressor_impl; - std::shared_ptr m_pimpl; - }; - - } }}} diff --git a/Release/include/cpprest/http_client.h b/Release/include/cpprest/http_client.h index f5ad8fac70..9ccd19e61f 100644 --- a/Release/include/cpprest/http_client.h +++ b/Release/include/cpprest/http_client.h @@ -247,20 +247,22 @@ class http_client_config } /// - /// Checks if requesting a compressed response is turned on, the default is off. + /// Checks if requesting a compressed response using Content-Encoding is turned on, the default is off. /// - /// True if compressed response is enabled, false otherwise + /// True if a content-encoded compressed response is allowed, false otherwise bool request_compressed_response() const { return m_request_compressed; } /// - /// Request that the server responds with a compressed body. - /// If true, in cases where the server does not support compression, this will have no effect. + /// Request that the server respond with a compressed body using Content-Encoding; to use Transfer-Encoding, do not + /// set this, and specify a vector of pointers + /// to the set_decompress_factories method of the object for the request. + /// If true and the server does not support compression, this will have no effect. /// The response body is internally decompressed before the consumer receives the data. /// - /// True to turn on response body compression, false otherwise. + /// True to turn on content-encoded response body compression, false otherwise. /// Please note there is a performance cost due to copying the request data. Currently only supported on Windows and OSX. void set_request_compressed_response(bool request_compressed) { diff --git a/Release/include/cpprest/http_compression.h b/Release/include/cpprest/http_compression.h new file mode 100644 index 0000000000..87b1d5dda8 --- /dev/null +++ b/Release/include/cpprest/http_compression.h @@ -0,0 +1,329 @@ +/*** + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: Compression and decompression interfaces + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ +#pragma once + +namespace web +{ +namespace http +{ +namespace compression +{ +/// +/// Hint as to whether a compress or decompress call is meant to be the last for a particular HTTP request or reply +/// +enum operation_hint +{ + is_last, // Used for the expected last compress() call, or for an expected single decompress() call + has_more // Used when further compress() calls will be made, or when multiple decompress() calls may be required +}; + +/// +/// Result structure for asynchronous compression and decompression operations +/// +struct operation_result +{ + size_t input_bytes_processed; // From the input buffer + size_t output_bytes_produced; // To the output buffer + bool done; // For compress, set when 'last' is true and there was enough space to complete compression; + // for decompress, set if the end of the decompression stream has been reached +}; + +/// +/// Compression interface for use with HTTP requests +/// +class compress_provider +{ +public: + virtual const utility::string_t& algorithm() const = 0; + virtual size_t compress(const uint8_t* input, + size_t input_size, + uint8_t* output, + size_t output_size, + operation_hint hint, + size_t& input_bytes_processed, + bool* done = nullptr) = 0; + virtual pplx::task compress( + const uint8_t* input, size_t input_size, uint8_t* output, size_t output_size, operation_hint hint) = 0; + virtual void reset() = 0; + virtual ~compress_provider() = default; +}; + +/// +/// Decompression interface for use with HTTP requests +/// +class decompress_provider +{ +public: + virtual const utility::string_t& algorithm() const = 0; + virtual size_t decompress(const uint8_t* input, + size_t input_size, + uint8_t* output, + size_t output_size, + operation_hint hint, + size_t& input_bytes_processed, + bool* done = nullptr) = 0; + virtual pplx::task decompress( + const uint8_t* input, size_t input_size, uint8_t* output, size_t output_size, operation_hint hint) = 0; + virtual void reset() = 0; + virtual ~decompress_provider() = default; +}; + +/// +/// Factory interface for compressors for use with received HTTP requests +/// +class compress_factory +{ +public: + virtual const utility::string_t& algorithm() const = 0; + virtual std::unique_ptr make_compressor() const = 0; + virtual ~compress_factory() = default; +}; + +/// +/// Factory interface for decompressors for use with HTTP requests +/// +class decompress_factory +{ +public: + virtual const utility::string_t& algorithm() const = 0; + virtual const uint16_t weight() const = 0; + virtual std::unique_ptr make_decompressor() const = 0; + virtual ~decompress_factory() = default; +}; + +/// +/// Built-in compression support +/// +namespace builtin +{ +/// +/// Test whether cpprestsdk was built with built-in compression support +/// True if cpprestsdk was built with built-in compression support, and false if not. +/// +_ASYNCRTIMP bool supported(); + +/// +// String constants for each built-in compression algorithm, for convenient use with the factory functions +/// +class algorithm +{ +public: + _ASYNCRTIMP static const utility::string_t GZIP; + _ASYNCRTIMP static const utility::string_t DEFLATE; + _ASYNCRTIMP static const utility::string_t BROTLI; + + /// + /// Test whether cpprestsdk was built with built-in compression support and + /// the supplied string matches a supported built-in algorithm + /// The name of the algorithm to test for built-in support. + /// True if cpprestsdk was built with built-in compression support and + /// the supplied string matches a supported built-in algorithm, and false if not. + /// + _ASYNCRTIMP static bool supported(const utility::string_t& algorithm); + +private: + algorithm() {} +}; + +/// +/// Factory function to instantiate a built-in compression provider with default parameters by compression algorithm +/// name. +/// +/// The name of the algorithm for which to instantiate a provider. +/// +/// A caller-owned pointer to a provider of the requested-type, or to nullptr if no such built-in type exists. +/// +_ASYNCRTIMP std::unique_ptr make_compressor(const utility::string_t& algorithm); + +/// +/// Factory function to instantiate a built-in decompression provider with default parameters by compression algorithm +/// name. +/// +/// The name of the algorithm for which to instantiate a provider. +/// +/// A caller-owned pointer to a provider of the requested-type, or to nullptr if no such built-in type exists. +/// +_ASYNCRTIMP std::unique_ptr make_decompressor(const utility::string_t& algorithm); + +/// +/// Factory function to obtain a pointer to a built-in compression provider factory by compression algorithm name. +/// +/// The name of the algorithm for which to find a factory. +/// +/// A caller-owned pointer to a provider of the requested-type, or to nullptr if no such built-in type exists. +/// +_ASYNCRTIMP std::shared_ptr get_compress_factory(const utility::string_t& algorithm); + +/// +/// Factory function to obtain a pointer to a built-in decompression provider factory by compression algorithm name. +/// +/// The name of the algorithm for which to find a factory. +/// +/// A caller-owned pointer to a provider of the requested-type, or to nullptr if no such built-in type exists. +/// +_ASYNCRTIMP std::shared_ptr get_decompress_factory(const utility::string_t& algorithm); + +/// +// Factory function to instantiate a built-in gzip compression provider with caller-selected parameters. +/// +/// +/// A caller-owned pointer to a gzip compression provider, or to nullptr if the library was built without built-in +/// compression support. +/// +_ASYNCRTIMP std::unique_ptr make_gzip_compressor(int compressionLevel, + int method, + int strategy, + int memLevel); + +/// +// Factory function to instantiate a built-in deflate compression provider with caller-selected parameters. +/// +/// +/// A caller-owned pointer to a deflate compression provider, or to nullptr if the library was built without built-in +/// compression support.. +/// +_ASYNCRTIMP std::unique_ptr make_deflate_compressor(int compressionLevel, + int method, + int strategy, + int memLevel); + +/// +// Factory function to instantiate a built-in Brotli compression provider with caller-selected parameters. +/// +/// +/// A caller-owned pointer to a Brotli compression provider, or to nullptr if the library was built without built-in +/// compression support. +/// +_ASYNCRTIMP std::unique_ptr make_brotli_compressor(uint32_t window, uint32_t quality, uint32_t mode); +} // namespace builtin + +/// +/// Factory function to instantiate a compression provider factory by compression algorithm name. +/// +/// The name of the algorithm supported by the factory. Must match that returned by the +/// web::http::compression::compress_provider type instantiated by the factory's make_compressor function. +/// The supplied string is copied, and thus need not remain valid once the call returns. +/// A factory function to be used to instantiate a compressor matching the factory's +/// reported algorithm. +/// +/// A pointer to a generic provider factory implementation configured with the supplied parameters. +/// +/// +/// This method may be used to conveniently instantiate a factory object for a caller-selected compress_provider. +/// That provider may be of the caller's own design, or it may be one of the built-in types. As such, this method may +/// be helpful when a caller wishes to build vectors containing a mix of custom and built-in providers. +/// +_ASYNCRTIMP std::shared_ptr make_compress_factory( + const utility::string_t& algorithm, std::function()> make_compressor); + +/// +/// Factory function to instantiate a decompression provider factory by compression algorithm name. +/// +/// The name of the algorithm supported by the factory. Must match that returned by the +/// web::http::compression::decompress_provider type instantiated by the factory's make_decompressor function. +/// The supplied string is copied, and thus need not remain valid once the call returns. +/// A numeric weight for the compression algorithm, times 1000, for use as a "quality value" when +/// requesting that the server send a compressed response. Valid values are between 0 and 1000, inclusive, where higher +/// values indicate more preferred algorithms, and 0 indicates that the algorithm is not allowed; values greater than +/// 1000 are treated as 1000. +/// A factory function to be used to instantiate a decompressor matching the factory's +/// reported algorithm. +/// +/// A pointer to a generic provider factory implementation configured with the supplied parameters. +/// +/// +/// This method may be used to conveniently instantiate a factory object for a caller-selected +/// decompress_provider. That provider may be of the caller's own design, or it may be one of the built-in +/// types. As such, this method may be helpful when a caller wishes to change the weights of built-in provider types, +/// to use custom providers without explicitly implementing a decompress_factory, or to build vectors containing +/// a mix of custom and built-in providers. +/// +_ASYNCRTIMP std::shared_ptr make_decompress_factory( + const utility::string_t& algorithm, + uint16_t weight, + std::function()> make_decompressor); + +namespace details +{ +namespace builtin +{ +// Internal-only helper function +const std::vector> get_decompress_factories(); +} // namespace builtin + +/// +/// Header type enum for use with compressor and decompressor header parsing and building functions +/// +enum header_types +{ + transfer_encoding, + content_encoding, + te, + accept_encoding +}; + +/// +/// Factory function to instantiate an appropriate compression provider, if any. +/// +/// A TE or Accept-Encoding header to interpret. +/// Specifies the type of header whose contents are in the encoding parameter; valid values are +/// header_type::te and header_type::accept_encoding. +/// A compressor object of the caller's preferred (possibly custom) type, which is used if +/// possible. +/// A collection of factory objects for use in construction of an appropriate compressor, if +/// any. If empty or not supplied, the set of supported built-in compressors is used. +/// +/// A pointer to a compressor object that is acceptable per the supplied header, or to nullptr if no matching +/// algorithm is found. +/// +_ASYNCRTIMP std::unique_ptr get_compressor_from_header( + const utility::string_t& encoding, + header_types type, + const std::vector>& factories = std::vector>()); + +/// +/// Factory function to instantiate an appropriate decompression provider, if any. +/// +/// A Transfer-Encoding or Content-Encoding header to interpret. +/// Specifies the type of header whose contents are in the encoding parameter; valid values are +/// header_type::transfer_encoding and header_type::content_encoding. +/// A collection of factory objects for use in construction of an appropriate decompressor, +/// if any. If empty or not supplied, the set of supported built-in compressors is used. +/// +/// A pointer to a decompressor object that is acceptable per the supplied header, or to nullptr if no matching +/// algorithm is found. +/// +_ASYNCRTIMP std::unique_ptr get_decompressor_from_header( + const utility::string_t& encoding, + header_types type, + const std::vector>& factories = + std::vector>()); + +/// +/// Helper function to compose a TE or Accept-Encoding header with supported, and possibly ranked, compression +/// algorithms. +/// +/// Specifies the type of header to be built; valid values are header_type::te and +/// header_type::accept_encoding. +/// A collection of factory objects for use in header construction. If empty or not +/// supplied, the set of supported built-in compressors is used. +/// +/// A well-formed header, without the header name, specifying the acceptable ranked compression types. +/// +_ASYNCRTIMP utility::string_t build_supported_header(header_types type, + const std::vector>& factories = + std::vector>()); +} // namespace details +} // namespace compression +} // namespace http +} // namespace web diff --git a/Release/include/cpprest/http_msg.h b/Release/include/cpprest/http_msg.h index b85e98ff42..85840b6836 100644 --- a/Release/include/cpprest/http_msg.h +++ b/Release/include/cpprest/http_msg.h @@ -26,6 +26,7 @@ #include "cpprest/asyncrt_utils.h" #include "cpprest/streams.h" #include "cpprest/containerstream.h" +#include "cpprest/http_compression.h" namespace web { @@ -338,6 +339,38 @@ class http_msg_base /// const concurrency::streams::ostream & outstream() const { return m_outStream; } + /// + /// Sets the compressor for the message body + /// + void set_compressor(std::unique_ptr compressor) + { + m_compressor = std::move(compressor); + } + + /// + /// Gets the compressor for the message body, if any + /// + std::unique_ptr &compressor() + { + return m_compressor; + } + + /// + /// Sets the collection of factory classes for decompressors for use with the message body + /// + void set_decompress_factories(const std::vector> &factories) + { + m_decompressors = factories; + } + + /// + /// Gets the collection of factory classes for decompressors to be used to decompress the message body, if any + /// + const std::vector> &decompress_factories() + { + return m_decompressors; + } + const pplx::task_completion_event & _get_data_available() const { return m_data_available; } /// @@ -345,6 +378,20 @@ class http_msg_base /// _ASYNCRTIMP void _prepare_to_receive_data(); + + /// + /// Determine the remaining input stream length + /// + /// + /// size_t::max if the stream's remaining length cannot be determined + /// length if the stream's remaining length (which may be 0) can be determined + /// + /// + /// This routine should only be called after a msg (request/response) has been + /// completely constructed. + /// + _ASYNCRTIMP size_t _get_stream_length(); + /// /// Determine the content length /// @@ -359,8 +406,27 @@ class http_msg_base /// _ASYNCRTIMP size_t _get_content_length(); + /// + /// Determine the content length, and, if necessary, manage compression in the Transfer-Encoding header + /// + /// + /// size_t::max if there is content with unknown length (transfer_encoding:chunked) + /// 0 if there is no content + /// length if there is content with known length + /// + /// + /// This routine is like _get_content_length, except that it adds a compression algorithm to + /// the Trasfer-Length header if compression is configured. It throws if a Transfer-Encoding + /// header exists and does not match the one it generated. + /// + _ASYNCRTIMP size_t _get_content_length_and_set_compression(); + protected: + std::unique_ptr m_compressor; + std::unique_ptr m_decompressor; + std::vector> m_decompressors; + /// /// Stream to read the message body. /// By default this is an invalid stream. The user could set the instream on @@ -386,6 +452,8 @@ class http_msg_base /// The TCE is used to signal the availability of the message body. pplx::task_completion_event m_data_available; + + size_t _get_content_length(bool honor_compression); }; /// @@ -1149,6 +1217,94 @@ class http_request return _m_impl->set_response_stream(stream); } + /// + /// Sets a compressor that will be used to compress the body of the HTTP message as it is sent. + /// + /// A pointer to an instantiated compressor of the desired type. + /// + /// This cannot be used in conjunction with any other means of compression. The Transfer-Encoding + /// header will be managed internally, and must not be set by the client. + /// + void set_compressor(std::unique_ptr compressor) + { + return _m_impl->set_compressor(std::move(compressor)); + } + + /// + /// Sets a compressor that will be used to compress the body of the HTTP message as it is sent. + /// + /// The built-in compression algorithm to use. + /// + /// True if a built-in compressor was instantiated, otherwise false. + /// + /// + /// This cannot be used in conjunction with any other means of compression. The Transfer-Encoding + /// header will be managed internally, and must not be set by the client. + /// + bool set_compressor(utility::string_t algorithm) + { + _m_impl->set_compressor(http::compression::builtin::make_compressor(algorithm)); + return (bool)_m_impl->compressor(); + } + + /// + /// Gets the compressor to be used to compress the message body, if any. + /// + /// + /// The compressor itself. + /// + std::unique_ptr &compressor() + { + return _m_impl->compressor(); + } + + /// + /// Sets the default collection of built-in factory classes for decompressors that may be used to + /// decompress the body of the HTTP message as it is received, effectively enabling decompression. + /// + /// The collection of factory classes for allowable decompressors. The + /// supplied vector itself need not remain valid after the call returns. + /// + /// This default collection is implied if request_compressed_response() is set in the associated + /// client::http_client_config and neither overload of this method has been called. + /// + /// This cannot be used in conjunction with any external means of decompression. The TE and Accept-Encoding + /// headers must not be set by the client, as they will be managed internally as appropriate. + /// + _ASYNCRTIMP void set_decompress_factories(); + + /// + /// Sets a collection of factory classes for decompressors that may be used to decompress the + /// body of the HTTP message as it is received, effectively enabling decompression. + /// + /// + /// If set, this collection takes the place of the built-in compression providers. It may contain + /// custom factory classes and/or factory classes for built-in providers, and may be used to adjust + /// the weights of the built-in providers, which default to 500 (i.e. "q=0.500"). + /// + /// This cannot be used in conjunction with any external means of decompression. The TE and Accept-Encoding + /// headers must not be set by the client, as they will be managed internally as appropriate. + /// + void set_decompress_factories(const std::vector> &factories) + { + return _m_impl->set_decompress_factories(factories); + } + + /// + /// Gets the collection of factory classes for decompressors to be used to decompress the message body, if any. + /// + /// + /// The collection of factory classes itself. + /// + /// + /// This cannot be used in conjunction with any other means of decompression. The TE + /// header must not be set by the client, as it will be managed internally. + /// + const std::vector> &decompress_factories() const + { + return _m_impl->decompress_factories(); + } + /// /// Defines a callback function that will be invoked for every chunk of data uploaded or downloaded /// as part of the request. diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index a34605bda2..a748698a45 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -21,6 +21,7 @@ set(SOURCES http/common/internal_http_helpers.h http/common/http_helpers.cpp http/common/http_msg.cpp + http/common/http_compression.cpp http/listener/http_listener.cpp http/listener/http_listener_msg.cpp http/listener/http_server_api.cpp @@ -75,6 +76,12 @@ if(CPPREST_EXCLUDE_COMPRESSION) else() cpprest_find_zlib() target_link_libraries(cpprest PRIVATE cpprestsdk_zlib_internal) + if(CPPREST_EXCLUDE_BROTLI) + target_compile_definitions(cpprest PRIVATE -DCPPREST_EXCLUDE_BROTLI=1) + else() + cpprest_find_brotli() + target_link_libraries(cpprest PRIVATE cpprestsdk_brotli_internal) + endif() endif() # PPLX component @@ -232,6 +239,7 @@ endif() if(CPPREST_INSTALL) set(CPPREST_USES_BOOST OFF) set(CPPREST_USES_ZLIB OFF) + set(CPPREST_USES_BROTLI OFF) set(CPPREST_USES_OPENSSL OFF) set(CPPREST_TARGETS cpprest) @@ -243,6 +251,10 @@ if(CPPREST_INSTALL) list(APPEND CPPREST_TARGETS cpprestsdk_zlib_internal) set(CPPREST_USES_ZLIB ON) endif() + if(TARGET cpprestsdk_brotli_internal) + list(APPEND CPPREST_TARGETS cpprestsdk_brotli_internal) + set(CPPREST_USES_BROTLI ON) + endif() if(TARGET cpprestsdk_openssl_internal) list(APPEND CPPREST_TARGETS cpprestsdk_openssl_internal) set(CPPREST_USES_OPENSSL ON) diff --git a/Release/src/http/client/http_client.cpp b/Release/src/http/client/http_client.cpp index 2963fae3c2..89eaa4941a 100644 --- a/Release/src/http/client/http_client.cpp +++ b/Release/src/http/client/http_client.cpp @@ -96,42 +96,57 @@ void request_context::report_exception(std::exception_ptr exceptionPtr) finish(); } -bool request_context::handle_content_encoding_compression() +bool request_context::handle_compression() { - if (web::http::details::compression::stream_decompressor::is_supported() && m_http_client->client_config().request_compressed_response()) + // If the response body is compressed we will read the encoding header and create a decompressor object which will later decompress the body + try { - // If the response body is compressed we will read the encoding header and create a decompressor object which will later decompress the body - auto&& headers = m_response.headers(); - auto it_ce = headers.find(web::http::header_names::content_encoding); - if (it_ce != headers.end()) + utility::string_t encoding; + http_headers &headers = m_response.headers(); + + // Note that some headers, for example "Transfer-Encoding: chunked", may legitimately not produce a decompressor + if (m_http_client->client_config().request_compressed_response() && headers.match(web::http::header_names::content_encoding, encoding)) + { + // Note that, while Transfer-Encoding (chunked only) is valid with Content-Encoding, + // we don't need to look for it here because winhttp de-chunks for us in that case + m_decompressor = compression::details::get_decompressor_from_header(encoding, compression::details::header_types::content_encoding, m_request.decompress_factories()); + } + else if (!m_request.decompress_factories().empty() && headers.match(web::http::header_names::transfer_encoding, encoding)) { - auto alg = web::http::details::compression::stream_decompressor::to_compression_algorithm(it_ce->second); - - if (alg != web::http::details::compression::compression_algorithm::invalid) - { - m_decompressor = utility::details::make_unique(alg); - } - else - { - report_exception( - http_exception("Unsupported compression algorithm in the Content-Encoding header: " - + utility::conversions::to_utf8string(it_ce->second))); - return false; - } + m_decompressor = compression::details::get_decompressor_from_header(encoding, compression::details::header_types::transfer_encoding, m_request.decompress_factories()); } } + catch (...) + { + report_exception(std::current_exception()); + return false; + } + return true; } -utility::string_t request_context::get_accept_encoding_header() const +utility::string_t request_context::get_compression_header() const { utility::string_t headers; - // Add the header needed to request a compressed response if supported on this platform and it has been specified in the config - if (web::http::details::compression::stream_decompressor::is_supported() - && m_http_client->client_config().request_compressed_response()) + + // Add the correct header needed to request a compressed response if supported + // on this platform and it has been specified in the config and/or request + if (m_http_client->client_config().request_compressed_response()) + { + if (!m_request.decompress_factories().empty() || web::http::compression::builtin::supported()) + { + // Accept-Encoding -- request Content-Encoding from the server + headers.append(header_names::accept_encoding + U(": ")); + headers.append(compression::details::build_supported_header(compression::details::header_types::accept_encoding, m_request.decompress_factories())); + headers.append(U("\r\n")); + } + } + else if (!m_request.decompress_factories().empty()) { - headers.append(U("Accept-Encoding: ")); - headers.append(web::http::details::compression::stream_decompressor::known_algorithms()); + // TE -- request Transfer-Encoding from the server + headers.append(header_names::connection + U(": TE\r\n") + // Required by Section 4.3 of RFC-7230 + header_names::te + U(": ")); + headers.append(compression::details::build_supported_header(compression::details::header_types::te, m_request.decompress_factories())); headers.append(U("\r\n")); } diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index e3ea15c9ff..893d36d74d 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -850,12 +850,12 @@ class asio_context final : public request_context, public std::enable_shared_fro extra_headers.append(ctx->generate_basic_auth_header()); } - extra_headers += utility::conversions::to_utf8string(ctx->get_accept_encoding_header()); + extra_headers += utility::conversions::to_utf8string(ctx->get_compression_header()); // Check user specified transfer-encoding. std::string transferencoding; if (ctx->m_request.headers().match(header_names::transfer_encoding, transferencoding) && - transferencoding == "chunked") + boost::icontains(transferencoding, U("chunked"))) { ctx->m_needChunked = true; } @@ -1394,7 +1394,7 @@ class asio_context final : public request_context, public std::enable_shared_fro if (boost::iequals(name, header_names::transfer_encoding)) { - needChunked = boost::iequals(value, U("chunked")); + needChunked = boost::icontains(value, U("chunked")); } if (boost::iequals(name, header_names::connection)) @@ -1415,7 +1415,7 @@ class asio_context final : public request_context, public std::enable_shared_fro // TCP stream - set it size_t max. m_response.headers().match(header_names::content_length, m_content_length); - if (!this->handle_content_encoding_compression()) + if (!this->handle_compression()) { // false indicates report_exception was called return; @@ -1518,6 +1518,52 @@ class asio_context final : public request_context, public std::enable_shared_fro } } + bool decompress(const uint8_t* input, size_t input_size, std::vector& output) + { + size_t processed; + size_t got; + size_t inbytes; + size_t outbytes; + bool done; + + // Need to guard against attempting to decompress when we're already finished or encountered an error! + if (input == nullptr || input_size == 0) + { + return false; + } + + inbytes = 0; + outbytes = 0; + done = false; + try + { + output.resize(input_size * 3); + do + { + if (inbytes) + { + output.resize(output.size() + (input_size > 1024 ? input_size : 1024)); + } + got = m_decompressor->decompress(input + inbytes, + input_size - inbytes, + output.data() + outbytes, + output.size() - outbytes, + web::http::compression::operation_hint::has_more, + processed, + &done); + inbytes += processed; + outbytes += got; + } while (got && !done); + output.resize(outbytes); + } + catch (...) + { + return false; + } + + return true; + } + void handle_chunk(const boost::system::error_code& ec, int to_read) { if (!ec) @@ -1550,10 +1596,11 @@ class asio_context final : public request_context, public std::enable_shared_fro const auto this_request = shared_from_this(); if (m_decompressor) { - auto decompressed = m_decompressor->decompress( - boost::asio::buffer_cast(m_body_buf.data()), to_read); + std::vector decompressed; - if (m_decompressor->has_error()) + bool boo = + decompress(boost::asio::buffer_cast(m_body_buf.data()), to_read, decompressed); + if (!boo) { report_exception(std::runtime_error("Failed to decompress the response body")); return; @@ -1574,8 +1621,7 @@ class asio_context final : public request_context, public std::enable_shared_fro { // Move the decompressed buffer into a shared_ptr to keep it alive until putn_nocopy completes. // When VS 2013 support is dropped, this should be changed to a unique_ptr plus a move capture. - using web::http::details::compression::data_buffer; - auto shared_decompressed = std::make_shared(std::move(decompressed)); + auto shared_decompressed = std::make_shared>(std::move(decompressed)); writeBuffer.putn_nocopy(shared_decompressed->data(), shared_decompressed->size()) .then([this_request, to_read, shared_decompressed AND_CAPTURE_MEMBER_FUNCTION_POINTERS]( @@ -1670,10 +1716,11 @@ class asio_context final : public request_context, public std::enable_shared_fro if (m_decompressor) { - auto decompressed = - m_decompressor->decompress(boost::asio::buffer_cast(m_body_buf.data()), read_size); + std::vector decompressed; - if (m_decompressor->has_error()) + bool boo = + decompress(boost::asio::buffer_cast(m_body_buf.data()), read_size, decompressed); + if (!boo) { this_request->report_exception(std::runtime_error("Failed to decompress the response body")); return; @@ -1704,8 +1751,7 @@ class asio_context final : public request_context, public std::enable_shared_fro { // Move the decompressed buffer into a shared_ptr to keep it alive until putn_nocopy completes. // When VS 2013 support is dropped, this should be changed to a unique_ptr plus a move capture. - using web::http::details::compression::data_buffer; - auto shared_decompressed = std::make_shared(std::move(decompressed)); + auto shared_decompressed = std::make_shared>(std::move(decompressed)); writeBuffer.putn_nocopy(shared_decompressed->data(), shared_decompressed->size()) .then([this_request, read_size, shared_decompressed AND_CAPTURE_MEMBER_FUNCTION_POINTERS]( @@ -1715,7 +1761,7 @@ class asio_context final : public request_context, public std::enable_shared_fro { writtenSize = op.get(); this_request->m_downloaded += static_cast(read_size); - this_request->m_body_buf.consume(writtenSize); + this_request->m_body_buf.consume(read_size); this_request->async_read_until_buffersize( static_cast(std::min( static_cast(this_request->m_http_client->client_config().chunksize()), diff --git a/Release/src/http/client/http_client_impl.h b/Release/src/http/client/http_client_impl.h index 7b6c974a0d..067233ab63 100644 --- a/Release/src/http/client/http_client_impl.h +++ b/Release/src/http/client/http_client_impl.h @@ -72,10 +72,10 @@ class request_context /// Set m_decompressor based on the response headers, or call report_exception /// false on failure - bool handle_content_encoding_compression(); + bool handle_compression(); /// Append an Accept-Encoding header if requested by the http_client settings - utility::string_t get_accept_encoding_header() const; + utility::string_t get_compression_header() const; concurrency::streams::streambuf _get_writebuffer(); @@ -95,7 +95,7 @@ class request_context // Registration for cancellation notification if enabled. pplx::cancellation_token_registration m_cancellationRegistration; - std::unique_ptr m_decompressor; + std::unique_ptr m_decompressor; protected: diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index a1f69ab215..d60f7ef1f5 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -182,9 +182,10 @@ class memory_holder { uint8_t* m_externalData; std::vector m_internalData; + size_t m_length; public: - memory_holder() : m_externalData(nullptr) + memory_holder() : m_externalData(nullptr), m_length(0) { } @@ -197,10 +198,11 @@ class memory_holder m_externalData = nullptr; } - inline void reassign_to(_In_opt_ uint8_t *block) + inline void reassign_to(_In_opt_ uint8_t *block, size_t length) { assert(block != nullptr); m_externalData = block; + m_length = length; } inline bool is_internally_allocated() const @@ -212,6 +214,11 @@ class memory_holder { return is_internally_allocated() ? &m_internalData[0] : m_externalData ; } + + inline size_t length() const + { + return is_internally_allocated() ? m_internalData.size() : m_length; + } }; // Possible ways a message body can be sent/received. @@ -245,7 +252,7 @@ class winhttp_request_context final : public request_context if (block == nullptr) m_body_data.allocate_space(length); else - m_body_data.reassign_to(block); + m_body_data.reassign_to(block, length); } void allocate_reply_space(_In_opt_ uint8_t *block, size_t length) @@ -253,7 +260,7 @@ class winhttp_request_context final : public request_context if (block == nullptr) m_body_data.allocate_space(length); else - m_body_data.reassign_to(block); + m_body_data.reassign_to(block, length); } bool is_externally_allocated() const @@ -286,8 +293,224 @@ class winhttp_request_context final : public request_context std::shared_ptr m_self_reference; memory_holder m_body_data; + // Compress/decompress-related processing state lives here + class compression_state + { + public: + compression_state() + : m_acquired(nullptr), m_bytes_read(0), m_bytes_processed(0), m_needs_flush(false), m_started(false), m_done(false), m_chunked(false) + { + } + + // Minimal state for on-the-fly decoding of "chunked" encoded data + class _chunk_helper + { + public: + _chunk_helper() + : m_bytes_remaining(0), m_chunk_size(true), m_chunk_delim(false), m_expect_linefeed(false), m_ignore(false), m_trailer(false) + { + } + + // Returns true if the end of chunked data has been reached, specifically whether the 0-length + // chunk and its trailing delimiter has been processed. Otherwise, offset and length bound the + // portion of buffer that represents a contiguous (and possibly partial) chunk of consumable + // data; offset+length is the total number of bytes processed from the buffer on this pass. + bool process_buffer(uint8_t *buffer, size_t buffer_size, size_t &offset, size_t &length) + { + bool done = false; + size_t n = 0; + size_t l = 0; + + while (n < buffer_size) + { + if (m_ignore) + { + if (m_expect_linefeed) + { + _ASSERTE(m_chunk_delim && m_trailer); + if (buffer[n] != '\n') + { + // The data stream does not conform to "chunked" encoding + throw http_exception(status_codes::BadRequest, "Transfer-Encoding malformed trailer"); + } + + // Look for further trailer fields or the end of the stream + m_expect_linefeed = false; + m_trailer = false; + } + else if (buffer[n] == '\r') + { + if (!m_trailer) + { + // We're at the end of the data we need to ignore + _ASSERTE(m_chunk_size || m_chunk_delim); + m_ignore = false; + m_chunk_delim = false; // this is only set if we're at the end of the message + } // else we're at the end of a trailer field + m_expect_linefeed = true; + } + else if (m_chunk_delim) + { + // We're processing (and ignoring) a trailer field + m_trailer = true; + } + } + else if (m_expect_linefeed) + { + // We've already seen a carriage return; confirm the linefeed + if (buffer[n] != '\n') + { + // The data stream does not conform to "chunked" encoding + throw http_exception(status_codes::BadRequest, "Transfer-Encoding malformed delimiter"); + } + if (m_chunk_size) + { + if (!m_bytes_remaining) + { + // We're processing the terminating "empty" chunk; there's + // no data, we just need to confirm the final chunk delimiter, + // possibly ignoring a trailer part along the way + m_ignore = true; + m_chunk_delim = true; + } // else we move on to the chunk data itself + m_chunk_size = false; + } + else + { + // Now we move on to the next chunk size + _ASSERTE(!m_bytes_remaining); + if (m_chunk_delim) + { + // We expect a chunk size next + m_chunk_size = true; + } + else + { + // We just processed the end-of-input delimiter + done = true; + } + m_chunk_delim = false; + } + m_expect_linefeed = false; + } + else if (m_chunk_delim) + { + // We're processing a post-chunk delimiter + if (buffer[n] != '\r') + { + // The data stream does not conform to "chunked" encoding + throw http_exception(status_codes::BadRequest, "Transfer-Encoding malformed chunk delimiter"); + } + + // We found the carriage return; look for the linefeed + m_expect_linefeed = true; + } + else if (m_chunk_size) + { + // We're processing an ASCII hexadecimal chunk size + if (buffer[n] >= 'a' && buffer[n] <= 'f') + { + m_bytes_remaining *= 16; + m_bytes_remaining += 10 + buffer[n] - 'a'; + } + else if (buffer[n] >= 'A' && buffer[n] <= 'F') + { + m_bytes_remaining *= 16; + m_bytes_remaining += 10 + buffer[n] - 'A'; + } + else if (buffer[n] >= '0' && buffer[n] <= '9') + { + m_bytes_remaining *= 16; + m_bytes_remaining += buffer[n] - '0'; + } + else if (buffer[n] == '\r') + { + // We've reached the end of the size, and there's no chunk extention + m_expect_linefeed = true; + } + else if (buffer[n] == ';') + { + // We've reached the end of the size, and there's a chunk extention; + // we don't support extensions, so we ignore them per RFC + m_ignore = true; + } + else + { + // The data stream does not conform to "chunked" encoding + throw http_exception(status_codes::BadRequest, "Transfer-Encoding malformed chunk size or extension"); + } + } + else + { + if (m_bytes_remaining) + { + // We're at the offset of a chunk of consumable data; let the caller process it + l = std::min(m_bytes_remaining, buffer_size-n); + m_bytes_remaining -= l; + if (!m_bytes_remaining) + { + // We're moving on to the post-chunk delimiter + m_chunk_delim = true; + } + } + else + { + // We've previously processed the terminating empty chunk and its + // trailing delimiter; skip the entire buffer, and inform the caller + n = buffer_size; + done = true; + } + + // Let the caller process the result + break; + } + + // Move on to the next byte + n++; + } + + offset = n; + length = l; + return buffer_size ? done : (!m_bytes_remaining && !m_chunk_size && !m_chunk_delim); + } + + private: + size_t m_bytes_remaining; // the number of bytes remaining in the chunk we're currently processing + bool m_chunk_size; // if true, we're processing a chunk size or its trailing delimiter + bool m_chunk_delim; // if true, we're processing a delimiter between a chunk and the next chunk's size + bool m_expect_linefeed; // if true, we're processing a delimiter, and we've already seen its carriage return + bool m_ignore; // if true, we're processing a chunk extension or trailer, which we don't support + bool m_trailer; // if true, we're processing (and ignoring) a trailer field; m_ignore is also true + }; + + std::vector m_buffer; // we read data from the stream into this before compressing + uint8_t *m_acquired; // we use this in place of m_buffer if the stream has directly-accessible data available + size_t m_bytes_read; // we most recently read this many bytes, which may be less than m_buffer.size() + size_t m_bytes_processed; // we've compressed this many bytes of m_bytes_read so far + bool m_needs_flush; // we've read and compressed all bytes, but the compressor still has compressed bytes to give us + bool m_started; // we've sent at least some number of bytes to m_decompressor + bool m_done; // we've read, compressed, and consumed all bytes + bool m_chunked; // if true, we need to decode and decompress a transfer-encoded message + size_t m_chunk_bytes; // un-decompressed bytes remaining in the most-recently-obtained data from m_chunk + std::unique_ptr<_chunk_helper> m_chunk; + } m_compression_state; + void cleanup() { + if (m_compression_state.m_acquired != nullptr) + { + // We may still hold a piece of the buffer if we encountered an exception; release it here + if (m_decompressor) + { + _get_writebuffer().commit(0); + } + else + { + _get_readbuffer().release(m_compression_state.m_acquired, m_compression_state.m_bytes_processed); + } + m_compression_state.m_acquired = nullptr; + } + if(m_request_handle != nullptr) { auto tmp_handle = m_request_handle; @@ -898,7 +1121,16 @@ class winhttp_client final : public _http_client_communicator return; } - const size_t content_length = msg._get_impl()->_get_content_length(); + size_t content_length; + try + { + content_length = msg._get_impl()->_get_content_length_and_set_compression(); + } + catch (...) + { + request->report_exception(std::current_exception()); + return; + } if (content_length > 0) { if ( msg.method() == http::methods::GET || msg.method() == http::methods::HEAD ) @@ -910,9 +1142,11 @@ class winhttp_client final : public _http_client_communicator // There is a request body that needs to be transferred. if (content_length == std::numeric_limits::max()) { - // The content length is unknown and the application set a stream. This is an - // indication that we will use transfer encoding chunked. + // The content length is not set and the application set a stream. This is an + // indication that we will use transfer encoding chunked. We still want to + // know that stream's effective length if possible for memory efficiency. winhttp_context->m_bodyType = transfer_encoding_chunked; + winhttp_context->m_remaining_to_write = msg._get_impl()->_get_stream_length(); } else { @@ -923,7 +1157,11 @@ class winhttp_client final : public _http_client_communicator } utility::string_t flattened_headers = web::http::details::flatten_http_headers(headers); - flattened_headers += winhttp_context->get_accept_encoding_header(); + if (winhttp_context->m_request.method() == http::methods::GET) + { + // Prepare to request a compressed response from the server if necessary. + flattened_headers += winhttp_context->get_compression_header(); + } // Add headers. if(!flattened_headers.empty()) @@ -1062,19 +1300,36 @@ class winhttp_client final : public _http_client_communicator else { // If bytes read is less than the chunk size this request is done. + // Is it really, though? The WinHttpReadData docs suggest that less can be returned regardless... const size_t chunkSize = pContext->m_http_client->client_config().chunksize(); - if (bytesRead < chunkSize && !firstRead) + std::unique_ptr &decompressor = pContext->m_decompressor; + if (!decompressor && bytesRead < chunkSize && !firstRead) { pContext->complete_request(pContext->m_downloaded); } else { - auto writebuf = pContext->_get_writebuffer(); - pContext->allocate_reply_space(writebuf.alloc(chunkSize), chunkSize); + uint8_t *buffer; + + if (!decompressor) + { + auto writebuf = pContext->_get_writebuffer(); + pContext->allocate_reply_space(writebuf.alloc(chunkSize), chunkSize); + buffer = pContext->m_body_data.get(); + } + else + { + // m_buffer holds the compressed data; we'll decompress into the caller's buffer later + if (pContext->m_compression_state.m_buffer.capacity() < chunkSize) + { + pContext->m_compression_state.m_buffer.reserve(chunkSize); + } + buffer = pContext->m_compression_state.m_buffer.data(); + } if (!WinHttpReadData( pContext->m_request_handle, - pContext->m_body_data.get(), + buffer, static_cast(chunkSize), nullptr)) { @@ -1087,11 +1342,38 @@ class winhttp_client final : public _http_client_communicator static void _transfer_encoding_chunked_write_data(_In_ winhttp_request_context * p_request_context) { - const size_t chunk_size = p_request_context->m_http_client->client_config().chunksize(); + size_t chunk_size; + std::unique_ptr &compressor = p_request_context->m_request.compressor(); - p_request_context->allocate_request_space(nullptr, chunk_size+http::details::chunked_encoding::additional_encoding_space); + // Set the chunk size up front; we need it before the lambda functions come into scope + if (compressor) + { + // We could allocate less than a chunk for the compressed data here, though that + // would result in more trips through this path for not-so-compressible data... + if (p_request_context->m_body_data.length() > http::details::chunked_encoding::additional_encoding_space) + { + // If we've previously allocated space for the compressed data, don't reduce it + chunk_size = p_request_context->m_body_data.length() - http::details::chunked_encoding::additional_encoding_space; + } + else if (p_request_context->m_remaining_to_write != std::numeric_limits::max()) + { + // Choose a semi-intelligent size based on how much total data is left to compress + chunk_size = std::min((size_t)p_request_context->m_remaining_to_write+128, p_request_context->m_http_client->client_config().chunksize()); + } + else + { + // Just base our allocation on the chunk size, since we don't have any other data available + chunk_size = p_request_context->m_http_client->client_config().chunksize(); + } + } + else + { + // We're not compressing; use the smaller of the remaining data (if known) and the configured (or default) chunk size + chunk_size = std::min((size_t)p_request_context->m_remaining_to_write, p_request_context->m_http_client->client_config().chunksize()); + } + p_request_context->allocate_request_space(nullptr, chunk_size + http::details::chunked_encoding::additional_encoding_space); - auto after_read = [p_request_context, chunk_size](pplx::task op) + auto after_read = [p_request_context, chunk_size, &compressor](pplx::task op) { size_t bytes_read; try @@ -1102,7 +1384,10 @@ class winhttp_client final : public _http_client_communicator { // We have raw memory here writing to a memory stream so it is safe to wait // since it will always be non-blocking. - p_request_context->m_readBufferCopy->putn_nocopy(&p_request_context->m_body_data.get()[http::details::chunked_encoding::data_offset], bytes_read).wait(); + if (!compressor) + { + p_request_context->m_readBufferCopy->putn_nocopy(&p_request_context->m_body_data.get()[http::details::chunked_encoding::data_offset], bytes_read).wait(); + } } } catch (...) @@ -1115,7 +1400,21 @@ class winhttp_client final : public _http_client_communicator size_t offset = http::details::chunked_encoding::add_chunked_delimiters(p_request_context->m_body_data.get(), chunk_size + http::details::chunked_encoding::additional_encoding_space, bytes_read); + if (!compressor && p_request_context->m_remaining_to_write != std::numeric_limits::max()) + { + if (bytes_read == 0 && p_request_context->m_remaining_to_write) + { + // The stream ended earlier than we detected it should + http_exception ex(U("Unexpected end of request body stream encountered before expected length met.")); + p_request_context->report_exception(ex); + return; + } + p_request_context->m_remaining_to_write -= bytes_read; + } + // Stop writing chunks if we reached the end of the stream. + // Note that we could detect end-of-stream based on !m_remaining_to_write, and insert + // the last (0) chunk if we have enough extra space... though we currently don't. if (bytes_read == 0) { p_request_context->m_bodyType = no_body; @@ -1140,7 +1439,171 @@ class winhttp_client final : public _http_client_communicator } }; - p_request_context->_get_readbuffer().getn(&p_request_context->m_body_data.get()[http::details::chunked_encoding::data_offset], chunk_size).then(after_read); + if (compressor) + { + auto do_compress = [p_request_context, chunk_size, &compressor](pplx::task op) -> pplx::task + { + size_t bytes_read; + + try + { + bytes_read = op.get(); + } + catch (...) + { + return pplx::task_from_exception(std::current_exception()); + } + _ASSERTE(bytes_read >= 0); + + uint8_t *buffer = p_request_context->m_compression_state.m_acquired; + if (buffer == nullptr) + { + buffer = p_request_context->m_compression_state.m_buffer.data(); + } + + web::http::compression::operation_hint hint = web::http::compression::operation_hint::has_more; + + if (bytes_read) + { + // An actual read always resets compression state for the next chunk + _ASSERTE(p_request_context->m_compression_state.m_bytes_processed == p_request_context->m_compression_state.m_bytes_read); + _ASSERTE(!p_request_context->m_compression_state.m_needs_flush); + p_request_context->m_compression_state.m_bytes_read = bytes_read; + p_request_context->m_compression_state.m_bytes_processed = 0; + if (p_request_context->m_readBufferCopy) + { + // If we've been asked to keep a copy of the raw data for restarts, do so here, pre-compression + p_request_context->m_readBufferCopy->putn_nocopy(buffer, bytes_read).wait(); + } + if (p_request_context->m_remaining_to_write == bytes_read) + { + // We've read to the end of the stream; finalize here if possible. We'll + // decrement the remaining count as we actually process the read buffer. + hint = web::http::compression::operation_hint::is_last; + } + } + else if (p_request_context->m_compression_state.m_needs_flush) + { + // All input has been consumed, but we still need to collect additional compressed output; + // this is done (in theory it can be multiple times) as a finalizing operation + hint = web::http::compression::operation_hint::is_last; + } + else if (p_request_context->m_compression_state.m_bytes_processed == p_request_context->m_compression_state.m_bytes_read) + { + if (p_request_context->m_remaining_to_write && p_request_context->m_remaining_to_write != std::numeric_limits::max()) + { + // The stream ended earlier than we detected it should + return pplx::task_from_exception(http_exception(U("Unexpected end of request body stream encountered before expected length met."))); + } + + // We think we're done; inform the compression library so it can finalize and/or give us any pending compressed bytes. + // Note that we may end up here multiple times if m_needs_flush is set, until all compressed bytes are drained. + hint = web::http::compression::operation_hint::is_last; + } + // else we're still compressing bytes from the previous read + + _ASSERTE(p_request_context->m_compression_state.m_bytes_processed <= p_request_context->m_compression_state.m_bytes_read); + + uint8_t *in = buffer + p_request_context->m_compression_state.m_bytes_processed; + size_t inbytes = p_request_context->m_compression_state.m_bytes_read - p_request_context->m_compression_state.m_bytes_processed; + return compressor->compress(in, inbytes, &p_request_context->m_body_data.get()[http::details::chunked_encoding::data_offset], chunk_size, hint) + .then([p_request_context, bytes_read, hint, chunk_size](pplx::task op) -> pplx::task + { + http::compression::operation_result r; + + try + { + r = op.get(); + } + catch (...) + { + return pplx::task_from_exception(std::current_exception()); + } + + if (hint == web::http::compression::operation_hint::is_last) + { + // We're done reading all chunks, but the compressor may still have compressed bytes to drain from previous reads + _ASSERTE(r.done || r.output_bytes_produced == chunk_size); + p_request_context->m_compression_state.m_needs_flush = !r.done; + p_request_context->m_compression_state.m_done = r.done; + } + + // Update the number of bytes compressed in this read chunk; if it's been fully compressed, + // we'll reset m_bytes_processed and m_bytes_read after reading the next chunk + p_request_context->m_compression_state.m_bytes_processed += r.input_bytes_processed; + _ASSERTE(p_request_context->m_compression_state.m_bytes_processed <= p_request_context->m_compression_state.m_bytes_read); + if (p_request_context->m_remaining_to_write != std::numeric_limits::max()) + { + _ASSERTE(p_request_context->m_remaining_to_write >= r.input_bytes_processed); + p_request_context->m_remaining_to_write -= r.input_bytes_processed; + } + + if (p_request_context->m_compression_state.m_acquired != nullptr && p_request_context->m_compression_state.m_bytes_processed == p_request_context->m_compression_state.m_bytes_read) + { + // Release the acquired buffer back to the streambuf at the earliest possible point + p_request_context->_get_readbuffer().release(p_request_context->m_compression_state.m_acquired, p_request_context->m_compression_state.m_bytes_processed); + p_request_context->m_compression_state.m_acquired = nullptr; + } + + return pplx::task_from_result(r.output_bytes_produced); + }); + }; + + if (p_request_context->m_compression_state.m_bytes_processed < p_request_context->m_compression_state.m_bytes_read || p_request_context->m_compression_state.m_needs_flush) + { + // We're still working on data from a previous read; continue compression without reading new data + do_compress(pplx::task_from_result(0)).then(after_read); + } + else if (p_request_context->m_compression_state.m_done) + { + // We just need to send the last (zero-length) chunk; there's no sense in going through the compression path + after_read(pplx::task_from_result(0)); + } + else + { + size_t length; + + // We need to read from the input stream, then compress before sending + if (p_request_context->_get_readbuffer().acquire(p_request_context->m_compression_state.m_acquired, length)) + { + if (length == 0) + { + if (p_request_context->_get_readbuffer().exception()) + { + p_request_context->report_exception(p_request_context->_get_readbuffer().exception()); + return; + } + else if (p_request_context->m_remaining_to_write && p_request_context->m_remaining_to_write != std::numeric_limits::max()) + { + // Unexpected end-of-stream. + p_request_context->report_error(GetLastError(), _XPLATSTR("Outgoing HTTP body stream ended early.")); + return; + } + } + else if (length > p_request_context->m_remaining_to_write) + { + // The stream grew, but we won't + length = p_request_context->m_remaining_to_write; + } + + do_compress(pplx::task_from_result(length)).then(after_read); + } + else + { + length = std::min((size_t)p_request_context->m_remaining_to_write, p_request_context->m_http_client->client_config().chunksize()); + if (p_request_context->m_compression_state.m_buffer.capacity() < length) + { + p_request_context->m_compression_state.m_buffer.reserve(length); + } + p_request_context->_get_readbuffer().getn(p_request_context->m_compression_state.m_buffer.data(), length).then(do_compress).then(after_read); + } + } + } + else + { + // We're not compressing; just read and chunk + p_request_context->_get_readbuffer().getn(&p_request_context->m_body_data.get()[http::details::chunked_encoding::data_offset], chunk_size).then(after_read); + } } static void _multiple_segment_write_data(_In_ winhttp_request_context * p_request_context) @@ -1272,7 +1735,21 @@ class winhttp_client final : public _http_client_communicator { return false; } + + // We successfully seeked back; now reset the compression state, if any, to match + if (p_request_context->m_request.compressor()) + { + try + { + p_request_context->m_request.compressor()->reset(); + } + catch (...) + { + return false; + } + } } + p_request_context->m_compression_state = winhttp_request_context::compression_state(); // If we got ERROR_WINHTTP_RESEND_REQUEST, the response header is not available, // we cannot call WinHttpQueryAuthSchemes and WinHttpSetCredentials. @@ -1346,7 +1823,16 @@ class winhttp_client final : public _http_client_communicator } // Reset the request body type since it might have already started sending. - const size_t content_length = request._get_impl()->_get_content_length(); + size_t content_length; + try + { + content_length = request._get_impl()->_get_content_length_and_set_compression(); + } + catch (...) + { + return false; + } + if (content_length > 0) { // There is a request body that needs to be transferred. @@ -1355,6 +1841,7 @@ class winhttp_client final : public _http_client_communicator // The content length is unknown and the application set a stream. This is an // indication that we will need to chunk the data. p_request_context->m_bodyType = transfer_encoding_chunked; + p_request_context->m_remaining_to_write = request._get_impl()->_get_stream_length(); } else { @@ -1551,11 +2038,17 @@ class winhttp_client final : public _http_client_communicator } } - if (!p_request_context->handle_content_encoding_compression()) + // Check whether the request is compressed, and if so, whether we're handling it. + if (!p_request_context->handle_compression()) { // false indicates report_exception was called return; } + if (p_request_context->m_decompressor && !p_request_context->m_http_client->client_config().request_compressed_response()) + { + p_request_context->m_compression_state.m_chunk = std::make_unique(); + p_request_context->m_compression_state.m_chunked = true; + } // Signal that the headers are available. p_request_context->complete_headers(); @@ -1582,25 +2075,30 @@ class winhttp_client final : public _http_client_communicator { // Status information contains pointer to DWORD containing number of bytes available. const DWORD num_bytes = *(PDWORD)statusInfo; + uint8_t *buffer; - if(num_bytes > 0) + if (num_bytes > 0) { if (p_request_context->m_decompressor) { - // Decompression is too slow to reliably do on this callback. Therefore we need to store it now in order to decompress it at a later stage in the flow. - // However, we want to eventually use the writebuf to store the decompressed body. Therefore we'll store the compressed body as an internal allocation in the request_context - p_request_context->allocate_reply_space(nullptr, num_bytes); + // Allocate space for the compressed data; we'll decompress it into the caller stream once it's been filled in + if (p_request_context->m_compression_state.m_buffer.capacity() < num_bytes) + { + p_request_context->m_compression_state.m_buffer.reserve(num_bytes); + } + buffer = p_request_context->m_compression_state.m_buffer.data(); } else { auto writebuf = p_request_context->_get_writebuffer(); p_request_context->allocate_reply_space(writebuf.alloc(num_bytes), num_bytes); + buffer = p_request_context->m_body_data.get(); } - // Read in body all at once. + // Read in available body data all at once. if(!WinHttpReadData( hRequestHandle, - p_request_context->m_body_data.get(), + buffer, num_bytes, nullptr)) { @@ -1610,6 +2108,21 @@ class winhttp_client final : public _http_client_communicator } else { + if (p_request_context->m_decompressor) + { + if (p_request_context->m_compression_state.m_chunked) + { + // We haven't seen the 0-length chunk and/or trailing delimiter that indicate the end of chunked input + p_request_context->report_exception(http_exception("Chunked response stream ended unexpectedly")); + return; + } + if (p_request_context->m_compression_state.m_started && !p_request_context->m_compression_state.m_done) + { + p_request_context->report_exception(http_exception("Received incomplete compressed stream")); + return; + } + } + // No more data available, complete the request. auto progress = p_request_context->m_request._get_impl()->_progress_handler(); if (progress) @@ -1647,68 +2160,240 @@ class winhttp_client final : public _http_client_communicator // If no bytes have been read, then this is the end of the response. if (bytesRead == 0) { + if (p_request_context->m_decompressor) + { + if (p_request_context->m_compression_state.m_chunked) + { + // We haven't seen the 0-length chunk and/or trailing delimiter that indicate the end of chunked input + p_request_context->report_exception(http_exception("Chunked response stream ended unexpectedly")); + return; + } + if (p_request_context->m_compression_state.m_started && !p_request_context->m_compression_state.m_done) + { + p_request_context->report_exception(http_exception("Received incomplete compressed stream")); + return; + } + } p_request_context->complete_request(p_request_context->m_downloaded); return; } auto writebuf = p_request_context->_get_writebuffer(); - // If we have compressed data it is stored in the local allocation of the p_request_context. We will store the decompressed buffer in the external allocation of the p_request_context. if (p_request_context->m_decompressor) { - web::http::details::compression::data_buffer decompressed = p_request_context->m_decompressor->decompress(p_request_context->m_body_data.get(), bytesRead); - - if (p_request_context->m_decompressor->has_error()) - { - p_request_context->report_exception(std::runtime_error("Failed to decompress the response body")); - return; - } + size_t chunk_size = std::max((size_t)bytesRead, p_request_context->m_http_client->client_config().chunksize()); + p_request_context->m_compression_state.m_bytes_read = static_cast(bytesRead); + p_request_context->m_compression_state.m_chunk_bytes = 0; - // We've decompressed this chunk of the body, need to now store it in the writebuffer. - auto decompressed_size = decompressed.size(); + // Note, some servers seem to send a first chunk of body data that decompresses to nothing, but + // initializes the decompression state; this produces no decompressed output. Subsequent chunks + // will then begin emitting decompressed body data. - if (decompressed_size > 0) + // Oddly enough, WinHttp doesn't de-chunk for us if "chunked" isn't the only + // encoding, so we need to do so on the fly as we process the received data + auto process_buffer = [chunk_size](winhttp_request_context *c, size_t bytes_produced, bool outer) -> bool { - auto p = writebuf.alloc(decompressed_size); - p_request_context->allocate_reply_space(p, decompressed_size); - std::memcpy(p_request_context->m_body_data.get(), &decompressed[0], decompressed_size); - } - // Note, some servers seem to send a first chunk of body data that decompresses to nothing but initializes the zlib decryption state. This produces no decompressed output. - // Subsequent chunks will then begin emmiting decompressed body data. + if (!c->m_compression_state.m_chunk_bytes) + { + if (c->m_compression_state.m_chunked) + { + size_t offset; + bool done; + + // Process the next portion of this piece of the transfer-encoded message + done = c->m_compression_state.m_chunk->process_buffer(c->m_compression_state.m_buffer.data()+c->m_compression_state.m_bytes_processed, c->m_compression_state.m_bytes_read-c->m_compression_state.m_bytes_processed, offset, c->m_compression_state.m_chunk_bytes); + + // Skip chunk-related metadata; it isn't relevant to decompression + _ASSERTE(c->m_compression_state.m_bytes_processed+offset <= c->m_compression_state.m_bytes_read); + c->m_compression_state.m_bytes_processed += offset; + + if (!c->m_compression_state.m_chunk_bytes) + { + if (done) + { + // We've processed/validated all bytes in this transfer-encoded message. + // Note that we currently ignore "extra" trailing bytes, i.e. c->m_compression_state.m_bytes_processed < c->m_compression_state.m_bytes_read + if (c->m_compression_state.m_done) + { + c->complete_request(c->m_downloaded); + return false; + } + else if (!outer && bytes_produced != chunk_size) + { + throw http_exception("Transfer ended before decompression completed"); + } + } + else if (!outer && bytes_produced != chunk_size) + { + // There should be more data to receive; look for it + c->m_compression_state.m_bytes_processed = 0; + read_next_response_chunk(c, static_cast(c->m_compression_state.m_bytes_read)); + return false; + } + } + } + else + { + _ASSERTE(!c->m_compression_state.m_bytes_processed || c->m_compression_state.m_bytes_processed == c->m_compression_state.m_bytes_read); + if (c->m_compression_state.m_done) + { + // Decompression is done; complete the request + c->complete_request(c->m_downloaded); + return false; + } + else if (c->m_compression_state.m_bytes_processed != c->m_compression_state.m_bytes_read) + { + // We still have more data to process in the current buffer + c->m_compression_state.m_chunk_bytes = c->m_compression_state.m_bytes_read - c->m_compression_state.m_bytes_processed; + } + else if (!outer && bytes_produced != chunk_size) + { + // There should be more data to receive; look for it + c->m_compression_state.m_bytes_processed = 0; + read_next_response_chunk(c, static_cast(c->m_compression_state.m_bytes_read)); + return false; + } + // Otherwise, we've processed all bytes in the input buffer, but there's a good chance that + // there are still decompressed bytes to emit; we'll do so before reading the next chunk + } + } - bytesRead = static_cast(decompressed_size); - } + // We're still processing the current message chunk + return true; + }; - // If the data was allocated directly from the buffer then commit, otherwise we still - // need to write to the response stream buffer. - if (p_request_context->is_externally_allocated()) - { - writebuf.commit(bytesRead); - read_next_response_chunk(p_request_context.get(), bytesRead); - } - else - { - writebuf.putn_nocopy(p_request_context->m_body_data.get(), bytesRead).then( - [hRequestHandle, p_request_context, bytesRead] (pplx::task op) + Concurrency::details::_do_while([p_request_context, chunk_size, process_buffer]() -> pplx::task { - size_t written = 0; - try { written = op.get(); } + uint8_t *buffer; + + try + { + if (!process_buffer(p_request_context.get(), 0, true)) + { + // The chunked request has been completely processed (or contains no data in the first place) + return pplx::task_from_result(false); + } + } catch (...) { - p_request_context->report_exception(std::current_exception()); - return; + // The outer do-while requires an explicit task return to activate the then() clause + return pplx::task_from_exception(std::current_exception()); } - // If we couldn't write everything, it's time to exit. - if (written != bytesRead) + // If it's possible to know how much post-compression data we're expecting (for instance if we can discern how + // much total data the ostream can support, we could allocate (or at least attempt to acquire) based on that + p_request_context->m_compression_state.m_acquired = p_request_context->_get_writebuffer().alloc(chunk_size); + if (p_request_context->m_compression_state.m_acquired) { - p_request_context->report_exception(std::runtime_error("response stream unexpectedly failed to write the requested number of bytes")); - return; + buffer = p_request_context->m_compression_state.m_acquired; + } + else + { + // The streambuf couldn't accommodate our request; we'll use m_body_data's + // internal vector as temporary storage, then putn() to the caller's stream + p_request_context->allocate_reply_space(nullptr, chunk_size); + buffer = p_request_context->m_body_data.get(); } - read_next_response_chunk(p_request_context.get(), bytesRead); + uint8_t *in = p_request_context->m_compression_state.m_buffer.data() + p_request_context->m_compression_state.m_bytes_processed; + size_t inbytes = p_request_context->m_compression_state.m_chunk_bytes; + if (inbytes) + { + p_request_context->m_compression_state.m_started = true; + } + return p_request_context->m_decompressor->decompress(in, inbytes, buffer, chunk_size, web::http::compression::operation_hint::has_more).then( + [p_request_context, buffer, chunk_size, process_buffer] (pplx::task op) + { + auto r = op.get(); + auto keep_going = [&r, process_buffer](winhttp_request_context *c) -> pplx::task + { + _ASSERTE(r.input_bytes_processed <= c->m_compression_state.m_chunk_bytes); + c->m_compression_state.m_chunk_bytes -= r.input_bytes_processed; + c->m_compression_state.m_bytes_processed += r.input_bytes_processed; + c->m_compression_state.m_done = r.done; + + try + { + // See if we still have more work to do for this section and/or for the response in general + return pplx::task_from_result(process_buffer(c, r.output_bytes_produced, false)); + } + catch (...) + { + return pplx::task_from_exception(std::current_exception()); + } + }; + + _ASSERTE(p_request_context->m_compression_state.m_bytes_processed+r.input_bytes_processed <= p_request_context->m_compression_state.m_bytes_read); + + if (p_request_context->m_compression_state.m_acquired != nullptr) + { + // We decompressed directly into the output stream + p_request_context->m_compression_state.m_acquired = nullptr; + p_request_context->_get_writebuffer().commit(r.output_bytes_produced); + return keep_going(p_request_context.get()); + } + + // We decompressed into our own buffer; let the stream copy the data + return p_request_context->_get_writebuffer().putn_nocopy(buffer, r.output_bytes_produced).then([p_request_context, r, keep_going](pplx::task op) { + if (op.get() != r.output_bytes_produced) + { + return pplx::task_from_exception(std::runtime_error("Response stream unexpectedly failed to write the requested number of bytes")); + } + return keep_going(p_request_context.get()); + }); + }); + }).then([p_request_context](pplx::task op) + { + try + { + bool ignored = op.get(); + } + catch (...) + { + // We're only here to pick up any exception that may have been thrown, and to clean up if needed + if (p_request_context->m_compression_state.m_acquired) + { + p_request_context->_get_writebuffer().commit(0); + p_request_context->m_compression_state.m_acquired = nullptr; + } + p_request_context->report_exception(std::current_exception()); + } }); } + else + { + // If the data was allocated directly from the buffer then commit, otherwise we still + // need to write to the response stream buffer. + if (p_request_context->is_externally_allocated()) + { + writebuf.commit(bytesRead); + read_next_response_chunk(p_request_context.get(), bytesRead); + } + else + { + writebuf.putn_nocopy(p_request_context->m_body_data.get(), bytesRead).then( + [hRequestHandle, p_request_context, bytesRead] (pplx::task op) + { + size_t written = 0; + try { written = op.get(); } + catch (...) + { + p_request_context->report_exception(std::current_exception()); + return; + } + + // If we couldn't write everything, it's time to exit. + if (written != bytesRead) + { + p_request_context->report_exception(std::runtime_error("response stream unexpectedly failed to write the requested number of bytes")); + return; + } + + read_next_response_chunk(p_request_context.get(), bytesRead); + }); + } + } return; } } diff --git a/Release/src/http/common/http_compression.cpp b/Release/src/http/common/http_compression.cpp new file mode 100644 index 0000000000..89840b8867 --- /dev/null +++ b/Release/src/http/common/http_compression.cpp @@ -0,0 +1,1110 @@ +/*** + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * HTTP Library: Compression and decompression interfaces + * + * For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ + +#include "stdafx.h" + +// CPPREST_EXCLUDE_COMPRESSION is set if we're on a platform that supports compression but we want to explicitly disable +// it. CPPREST_EXCLUDE_BROTLI is set if we want to explicitly disable Brotli compression support. +// CPPREST_EXCLUDE_WEBSOCKETS is a flag that now essentially means "no external dependencies". TODO: Rename + +#if __APPLE__ +#include "TargetConditionals.h" +#if defined(TARGET_OS_MAC) +#if !defined(CPPREST_EXCLUDE_COMPRESSION) +#define CPPREST_HTTP_COMPRESSION +#endif // !defined(CPPREST_EXCLUDE_COMPRESSION) +#endif // defined(TARGET_OS_MAC) +#elif defined(_WIN32) && (!defined(WINAPI_FAMILY) || WINAPI_PARTITION_DESKTOP) +#if !defined(CPPREST_EXCLUDE_WEBSOCKETS) && !defined(CPPREST_EXCLUDE_COMPRESSION) +#define CPPREST_HTTP_COMPRESSION +#endif // !defined(CPPREST_EXCLUDE_WEBSOCKETS) && !defined(CPPREST_EXCLUDE_COMPRESSION) +#endif + +#if defined(CPPREST_HTTP_COMPRESSION) +#include +#if !defined(CPPREST_EXCLUDE_BROTLI) +#define CPPREST_BROTLI_COMPRESSION +#endif // CPPREST_EXCLUDE_BROTLI +#if defined(CPPREST_BROTLI_COMPRESSION) +#include +#include +#endif // CPPREST_BROTLI_COMPRESSION +#endif + +namespace web +{ +namespace http +{ +namespace compression +{ +namespace builtin +{ +#if defined(CPPREST_HTTP_COMPRESSION) +// A shared base class for the gzip and deflate compressors +class zlib_compressor_base : public compress_provider +{ +public: + zlib_compressor_base(int windowBits, + int compressionLevel = Z_DEFAULT_COMPRESSION, + int method = Z_DEFLATED, + int strategy = Z_DEFAULT_STRATEGY, + int memLevel = MAX_MEM_LEVEL) + : m_algorithm(windowBits >= 16 ? algorithm::GZIP : algorithm::DEFLATE) + { + m_state = deflateInit2(&m_stream, compressionLevel, method, windowBits, memLevel, strategy); + } + + const utility::string_t& algorithm() const { return m_algorithm; } + + size_t compress(const uint8_t* input, + size_t input_size, + uint8_t* output, + size_t output_size, + operation_hint hint, + size_t& input_bytes_processed, + bool* done) + { + if (m_state == Z_STREAM_END || (hint != operation_hint::is_last && !input_size)) + { + input_bytes_processed = 0; + if (done) + { + *done = (m_state == Z_STREAM_END); + } + return 0; + } + + if (m_state != Z_OK && m_state != Z_BUF_ERROR && m_state != Z_STREAM_ERROR) + { + std::stringstream ss; + ss << "Prior unrecoverable compression stream error " << m_state; + throw std::runtime_error(std::move(ss.str())); + } + + m_stream.next_in = const_cast(input); + m_stream.avail_in = static_cast(input_size); + m_stream.next_out = const_cast(output); + m_stream.avail_out = static_cast(output_size); + + m_state = deflate(&m_stream, (hint == operation_hint::is_last) ? Z_FINISH : Z_PARTIAL_FLUSH); + if (m_state != Z_OK && m_state != Z_STREAM_ERROR && + !(hint == operation_hint::is_last && (m_state == Z_STREAM_END || m_state == Z_BUF_ERROR))) + { + std::stringstream ss; + ss << "Unrecoverable compression stream error " << m_state; + throw std::runtime_error(std::move(ss.str())); + } + + input_bytes_processed = input_size - m_stream.avail_in; + if (done) + { + *done = (m_state == Z_STREAM_END); + } + return output_size - m_stream.avail_out; + } + + pplx::task compress( + const uint8_t* input, size_t input_size, uint8_t* output, size_t output_size, operation_hint hint) + { + operation_result r; + + try + { + r.output_bytes_produced = + compress(input, input_size, output, output_size, hint, r.input_bytes_processed, &r.done); + } + catch (...) + { + pplx::task_completion_event ev; + ev.set_exception(std::current_exception()); + return pplx::create_task(ev); + } + + return pplx::task_from_result(r); + } + + void reset() + { + m_state = deflateReset(&m_stream); + if (m_state != Z_OK) + { + std::stringstream ss; + ss << "Failed to reset zlib compressor " << m_state; + throw std::runtime_error(std::move(ss.str())); + } + } + + ~zlib_compressor_base() { (void)deflateEnd(&m_stream); } + +private: + int m_state{Z_BUF_ERROR}; + z_stream m_stream{0}; + const utility::string_t& m_algorithm; +}; + +// A shared base class for the gzip and deflate decompressors +class zlib_decompressor_base : public decompress_provider +{ +public: + zlib_decompressor_base(int windowBits) : m_algorithm(windowBits >= 16 ? algorithm::GZIP : algorithm::DEFLATE) + { + m_state = inflateInit2(&m_stream, windowBits); + } + + const utility::string_t& algorithm() const { return m_algorithm; } + + size_t decompress(const uint8_t* input, + size_t input_size, + uint8_t* output, + size_t output_size, + operation_hint hint, + size_t& input_bytes_processed, + bool* done) + { + if (m_state == Z_STREAM_END || !input_size) + { + input_bytes_processed = 0; + if (done) + { + *done = (m_state == Z_STREAM_END); + } + return 0; + } + + if (m_state != Z_OK && m_state != Z_BUF_ERROR && m_state != Z_STREAM_ERROR) + { + std::stringstream ss; + ss << "Prior unrecoverable decompression stream error " << m_state; + throw std::runtime_error(std::move(ss.str())); + } + + m_stream.next_in = const_cast(input); + m_stream.avail_in = static_cast(input_size); + m_stream.next_out = const_cast(output); + m_stream.avail_out = static_cast(output_size); + + m_state = inflate(&m_stream, (hint == operation_hint::is_last) ? Z_FINISH : Z_PARTIAL_FLUSH); + if (m_state != Z_OK && m_state != Z_STREAM_ERROR && m_state != Z_STREAM_END && m_state != Z_BUF_ERROR) + { + // Z_BUF_ERROR is a success code for Z_FINISH, and the caller can continue as if operation_hint::is_last was + // not given + std::stringstream ss; + ss << "Unrecoverable decompression stream error " << m_state; + throw std::runtime_error(std::move(ss.str())); + } + + input_bytes_processed = input_size - m_stream.avail_in; + if (done) + { + *done = (m_state == Z_STREAM_END); + } + return output_size - m_stream.avail_out; + } + + pplx::task decompress( + const uint8_t* input, size_t input_size, uint8_t* output, size_t output_size, operation_hint hint) + { + operation_result r; + + try + { + r.output_bytes_produced = + decompress(input, input_size, output, output_size, hint, r.input_bytes_processed, &r.done); + } + catch (...) + { + pplx::task_completion_event ev; + ev.set_exception(std::current_exception()); + return pplx::create_task(ev); + } + + return pplx::task_from_result(r); + } + + void reset() + { + m_state = inflateReset(&m_stream); + if (m_state != Z_OK) + { + std::stringstream ss; + ss << "Failed to reset zlib decompressor " << m_state; + throw std::runtime_error(std::move(ss.str())); + } + } + + ~zlib_decompressor_base() { (void)inflateEnd(&m_stream); } + +private: + int m_state{Z_BUF_ERROR}; + z_stream m_stream{0}; + const utility::string_t& m_algorithm; +}; + +class gzip_compressor : public zlib_compressor_base +{ +public: + gzip_compressor() : zlib_compressor_base(31) // 15 is MAX_WBITS in zconf.h; add 16 for gzip + { + } + + gzip_compressor(int compressionLevel, int method, int strategy, int memLevel) + : zlib_compressor_base(31, compressionLevel, method, strategy, memLevel) + { + } +}; + +class gzip_decompressor : public zlib_decompressor_base +{ +public: + gzip_decompressor::gzip_decompressor() : zlib_decompressor_base(16) // gzip auto-detect + { + } +}; + +class deflate_compressor : public zlib_compressor_base +{ +public: + deflate_compressor() : zlib_compressor_base(15) // 15 is MAX_WBITS in zconf.h + { + } + + deflate_compressor(int compressionLevel, int method, int strategy, int memLevel) + : zlib_compressor_base(15, compressionLevel, method, strategy, memLevel) + { + } +}; + +class deflate_decompressor : public zlib_decompressor_base +{ +public: + deflate_decompressor() : zlib_decompressor_base(0) // deflate auto-detect + { + } +}; + +#if defined(CPPREST_BROTLI_COMPRESSION) +class brotli_compressor : public compress_provider +{ +public: + brotli_compressor(uint32_t window = BROTLI_DEFAULT_WINDOW, + uint32_t quality = BROTLI_DEFAULT_QUALITY, + uint32_t mode = BROTLI_DEFAULT_MODE) + : m_window(window), m_quality(quality), m_mode(mode) + { + (void)reset(); + } + + const utility::string_t& algorithm() const { return algorithm::BROTLI; } + + size_t compress(const uint8_t* input, + size_t input_size, + uint8_t* output, + size_t output_size, + operation_hint hint, + size_t& input_bytes_processed, + bool* done) + { + if (m_done || (hint != operation_hint::is_last && !input_size)) + { + input_bytes_processed = 0; + if (done) + { + *done = m_done; + } + return 0; + } + + if (m_state != BROTLI_TRUE) + { + throw std::runtime_error("Prior unrecoverable compression stream error"); + } + + const uint8_t* next_in = input; + size_t avail_in; + uint8_t* next_out = output; + size_t avail_out = output_size; + size_t total_out; + + if (BrotliEncoderHasMoreOutput(m_stream) == BROTLI_TRUE) + { + avail_in = 0; + do + { + m_state = BrotliEncoderCompressStream(m_stream, + (hint == operation_hint::is_last) ? BROTLI_OPERATION_FINISH + : BROTLI_OPERATION_FLUSH, + &avail_in, + &next_in, + &avail_out, + &next_out, + &total_out); + } while (m_state == BROTLI_TRUE && avail_out && BrotliEncoderHasMoreOutput(m_stream) == BROTLI_TRUE); + } + + if (m_state == BROTLI_TRUE && avail_out) + { + avail_in = input_size; + do + { + m_state = BrotliEncoderCompressStream(m_stream, + (hint == operation_hint::is_last) ? BROTLI_OPERATION_FINISH + : BROTLI_OPERATION_FLUSH, + &avail_in, + &next_in, + &avail_out, + &next_out, + &total_out); + } while (m_state == BROTLI_TRUE && avail_out && BrotliEncoderHasMoreOutput(m_stream) == BROTLI_TRUE); + } + + if (m_state != BROTLI_TRUE) + { + throw std::runtime_error("Unrecoverable compression stream error"); + } + + if (hint == operation_hint::is_last) + { + m_done = (BrotliEncoderIsFinished(m_stream) == BROTLI_TRUE); + } + + input_bytes_processed = input_size - avail_in; + if (done) + { + *done = m_done; + } + return output_size - avail_out; + } + + pplx::task compress( + const uint8_t* input, size_t input_size, uint8_t* output, size_t output_size, operation_hint hint) + { + operation_result r; + + try + { + r.output_bytes_produced = + compress(input, input_size, output, output_size, hint, r.input_bytes_processed, &r.done); + } + catch (...) + { + pplx::task_completion_event ev; + ev.set_exception(std::current_exception()); + return pplx::create_task(ev); + } + + return pplx::task_from_result(r); + } + + void reset() + { + if (m_stream) + { + BrotliEncoderDestroyInstance(m_stream); + } + + m_stream = BrotliEncoderCreateInstance(nullptr, nullptr, nullptr); + m_state = m_stream ? BROTLI_TRUE : BROTLI_FALSE; + + if (m_state == BROTLI_TRUE && m_window != BROTLI_DEFAULT_WINDOW) + { + m_state = BrotliEncoderSetParameter(m_stream, BROTLI_PARAM_LGWIN, m_window); + } + if (m_state == BROTLI_TRUE && m_quality != BROTLI_DEFAULT_QUALITY) + { + m_state = BrotliEncoderSetParameter(m_stream, BROTLI_PARAM_QUALITY, m_quality); + } + if (m_state == BROTLI_TRUE && m_mode != BROTLI_DEFAULT_MODE) + { + m_state = BrotliEncoderSetParameter(m_stream, BROTLI_PARAM_MODE, m_window); + } + + if (m_state != BROTLI_TRUE) + { + throw std::runtime_error("Failed to reset Brotli compressor"); + } + } + + ~brotli_compressor() + { + if (m_stream) + { + BrotliEncoderDestroyInstance(m_stream); + } + } + +private: + BROTLI_BOOL m_state{BROTLI_FALSE}; + BrotliEncoderState* m_stream{nullptr}; + bool m_done{false}; + uint32_t m_window; + uint32_t m_quality; + uint32_t m_mode; +}; + +class brotli_decompressor : public decompress_provider +{ +public: + brotli_decompressor() + { + try + { + reset(); + } + catch (...) + { + } + } + + const utility::string_t& algorithm() const { return algorithm::BROTLI; } + + size_t decompress(const uint8_t* input, + size_t input_size, + uint8_t* output, + size_t output_size, + operation_hint hint, + size_t& input_bytes_processed, + bool* done) + { + if (m_state == BROTLI_DECODER_RESULT_SUCCESS /* || !input_size*/) + { + input_bytes_processed = 0; + if (done) + { + *done = (m_state == BROTLI_DECODER_RESULT_SUCCESS); + } + return 0; + } + + if (m_state == BROTLI_DECODER_RESULT_ERROR) + { + throw std::runtime_error("Prior unrecoverable decompression stream error"); + } + + const uint8_t* next_in = input; + size_t avail_in = input_size; + uint8_t* next_out = output; + size_t avail_out = output_size; + size_t total_out; + + // N.B. we ignore 'hint' here. We could instead call BrotliDecoderDecompress() if it's set, but we'd either + // have to first allocate a guaranteed-large-enough buffer and then copy out of it, or we'd have to call + // reset() if it failed due to insufficient output buffer space (and we'd need to use + // BrotliDecoderGetErrorCode() to tell if that's why it failed) + m_state = BrotliDecoderDecompressStream(m_stream, &avail_in, &next_in, &avail_out, &next_out, &total_out); + if (m_state == BROTLI_DECODER_RESULT_ERROR) + { + throw std::runtime_error("Unrecoverable decompression stream error"); + } + + input_bytes_processed = input_size - avail_in; + if (done) + { + *done = (m_state == BROTLI_DECODER_RESULT_SUCCESS); + } + return output_size - avail_out; + } + + pplx::task decompress( + const uint8_t* input, size_t input_size, uint8_t* output, size_t output_size, operation_hint hint) + { + operation_result r; + + try + { + r.output_bytes_produced = + decompress(input, input_size, output, output_size, hint, r.input_bytes_processed, &r.done); + } + catch (...) + { + pplx::task_completion_event ev; + ev.set_exception(std::current_exception()); + return pplx::create_task(ev); + } + + return pplx::task_from_result(r); + } + + void reset() + { + if (m_stream) + { + BrotliDecoderDestroyInstance(m_stream); + } + + m_stream = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr); + m_state = m_stream ? BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT : BROTLI_DECODER_RESULT_ERROR; + + if (m_state != BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) + { + throw std::runtime_error("Failed to reset Brotli decompressor"); + } + } + + ~brotli_decompressor() + { + if (m_stream) + { + BrotliDecoderDestroyInstance(m_stream); + } + } + +private: + BrotliDecoderResult m_state{BROTLI_DECODER_RESULT_ERROR}; + BrotliDecoderState* m_stream{nullptr}; +}; +#endif // CPPREST_BROTLI_COMPRESSION +#endif // CPPREST_HTTP_COMPRESSION + +const utility::string_t algorithm::GZIP = _XPLATSTR("gzip"); +const utility::string_t algorithm::DEFLATE = _XPLATSTR("deflate"); +const utility::string_t algorithm::BROTLI = _XPLATSTR("br"); + +// Generic internal implementation of the compress_factory API +class generic_compress_factory : public compress_factory +{ +public: + generic_compress_factory(const utility::string_t& algorithm, + std::function()> make_compressor) + : _algorithm(algorithm), _make_compressor(make_compressor) + { + } + + const utility::string_t& algorithm() const { return _algorithm; } + + std::unique_ptr make_compressor() const { return _make_compressor(); } + +private: + const utility::string_t _algorithm; + std::function()> _make_compressor; +}; + +// Generic internal implementation of the decompress_factory API +class generic_decompress_factory : public decompress_factory +{ +public: + generic_decompress_factory(const utility::string_t& algorithm, + uint16_t weight, + std::function()> make_decompressor) + : _algorithm(algorithm), _weight(weight), _make_decompressor(make_decompressor) + { + } + + const utility::string_t& algorithm() const { return _algorithm; } + + const uint16_t weight() const { return _weight; } + + std::unique_ptr make_decompressor() const { return _make_decompressor(); } + +private: + const utility::string_t _algorithm; + uint16_t _weight; + std::function()> _make_decompressor; +}; + +// "Private" algorithm-to-factory tables for namespace static helpers +static const std::vector> g_compress_factories +#if defined(CPPREST_HTTP_COMPRESSION) + = {std::make_shared( + algorithm::GZIP, []() -> std::unique_ptr { return std::make_unique(); }), + std::make_shared( + algorithm::DEFLATE, + []() -> std::unique_ptr { return std::make_unique(); }), +#if defined(CPPREST_BROTLI_COMPRESSION) + std::make_shared( + algorithm::BROTLI, + []() -> std::unique_ptr { return std::make_unique(); }) +#endif // CPPREST_BROTLI_COMPRESSION +}; +#else // CPPREST_HTTP_COMPRESSION + ; +#endif // CPPREST_HTTP_COMPRESSION + +static const std::vector> g_decompress_factories +#if defined(CPPREST_HTTP_COMPRESSION) + = {std::make_shared( + algorithm::GZIP, + 500, + []() -> std::unique_ptr { return std::make_unique(); }), + std::make_shared( + algorithm::DEFLATE, + 500, + []() -> std::unique_ptr { return std::make_unique(); }), +#if defined(CPPREST_BROTLI_COMPRESSION) + std::make_shared( + algorithm::BROTLI, + 500, + []() -> std::unique_ptr { return std::make_unique(); }) +#endif // CPPREST_BROTLI_COMPRESSION +}; +#else // CPPREST_HTTP_COMPRESSION + ; +#endif // CPPREST_HTTP_COMPRESSION + +bool supported() { return !g_compress_factories.empty(); } + +bool algorithm::supported(const utility::string_t& algorithm) +{ + auto size = g_compress_factories.size(); + + for (int i = 0; i < size; i++) + { + if (utility::details::str_iequal(algorithm, g_compress_factories[i]->algorithm())) + { + return true; + } + } + + return false; +} + +static std::unique_ptr _make_compressor( + const std::vector>& factories, const utility::string_t& algorithm) +{ + auto size = factories.size(); + + for (int i = 0; i < size; i++) + { + auto factory = factories[i].get(); + if (factory && utility::details::str_iequal(algorithm, factory->algorithm())) + { + return factory->make_compressor(); + } + } + + return std::unique_ptr(); +} + +std::unique_ptr make_compressor(const utility::string_t& algorithm) +{ + return _make_compressor(g_compress_factories, algorithm); +} + +static std::unique_ptr _make_decompressor( + const std::vector>& factories, const utility::string_t& algorithm) +{ + auto size = factories.size(); + + for (int i = 0; i < size; i++) + { + auto factory = factories[i].get(); + if (factory && utility::details::str_iequal(algorithm, factory->algorithm())) + { + return factory->make_decompressor(); + } + } + + return std::unique_ptr(); +} + +std::unique_ptr make_decompressor(const utility::string_t& algorithm) +{ + return _make_decompressor(g_decompress_factories, algorithm); +} + +std::shared_ptr get_compress_factory(const utility::string_t& algorithm) +{ + auto size = g_compress_factories.size(); + + for (int i = 0; i < size; i++) + { + if (utility::details::str_iequal(algorithm, g_compress_factories[i]->algorithm())) + { + return g_compress_factories[i]; + } + } + + return std::shared_ptr(); +} + +std::shared_ptr get_decompress_factory(const utility::string_t& algorithm) +{ + auto size = g_decompress_factories.size(); + + for (int i = 0; i < size; i++) + { + if (utility::details::str_iequal(algorithm, g_decompress_factories[i]->algorithm())) + { + return g_decompress_factories[i]; + } + } + + return std::shared_ptr(); +} + +std::unique_ptr make_gzip_compressor(int compressionLevel, int method, int strategy, int memLevel) +{ +#if defined(CPPREST_HTTP_COMPRESSION) + return std::move(std::make_unique(compressionLevel, method, strategy, memLevel)); +#else // CPPREST_HTTP_COMPRESSION + return std::unique_ptr(); +#endif // CPPREST_HTTP_COMPRESSION +} + +std::unique_ptr make_deflate_compressor(int compressionLevel, int method, int strategy, int memLevel) +{ +#if defined(CPPREST_HTTP_COMPRESSION) + return std::move(std::make_unique(compressionLevel, method, strategy, memLevel)); +#else // CPPREST_HTTP_COMPRESSION + return std::unique_ptr(); +#endif // CPPREST_HTTP_COMPRESSION +} + +std::unique_ptr make_brotli_compressor(uint32_t window, uint32_t quality, uint32_t mode) +{ +#if defined(CPPREST_HTTP_COMPRESSION) && defined(CPPREST_BROTLI_COMPRESSION) + return std::move(std::make_unique(window, quality, mode)); +#else // CPPREST_BROTLI_COMPRESSION + return std::unique_ptr(); +#endif // CPPREST_BROTLI_COMPRESSION +} +} // namespace builtin + +std::shared_ptr make_compress_factory( + const utility::string_t& algorithm, std::function()> make_compressor) +{ + return std::make_shared(algorithm, make_compressor); +} + +std::shared_ptr make_decompress_factory( + const utility::string_t& algorithm, + uint16_t weight, + std::function()> make_decompressor) +{ + return std::make_shared(algorithm, weight, make_decompressor); +} + +namespace details +{ +namespace builtin +{ +const std::vector> get_decompress_factories() +{ + return web::http::compression::builtin::g_decompress_factories; +} +} // namespace builtin + +static bool is_http_whitespace(utility::char_t ch) { return ch == _XPLATSTR(" ")[0] || ch == _XPLATSTR("\t")[0]; } + +static void remove_surrounding_http_whitespace(const utility::string_t& encoding, size_t& start, size_t& length) +{ + while (length > 0 && is_http_whitespace(encoding.at(start))) + { + start++; + length--; + } + while (length > 0 && is_http_whitespace(encoding.at(start + length - 1))) + { + length--; + } +} + +std::unique_ptr get_compressor_from_header( + const utility::string_t& encoding, + header_types type, + const std::vector>& factories) +{ + const std::vector>& f = + factories.empty() ? web::http::compression::builtin::g_compress_factories : factories; + std::unique_ptr compressor; + struct _tuple + { + size_t start; + size_t length; + size_t rank; + } t; + std::vector<_tuple> tokens; + size_t highest; + size_t mark; + size_t end; + size_t n; + bool first; + + _ASSERTE(type == header_types::te || type == header_types::accept_encoding); + + // See https://tools.ietf.org/html/rfc7230#section-4.3 (TE) and + // https://tools.ietf.org/html/rfc7231#section-5.3.4 (Accept-Encoding) for details + + n = 0; + highest = 0; + first = true; + while (n != utility::string_t::npos) + { + // Tokenize by commas first + mark = encoding.find(_XPLATSTR(","), n); + t.start = n; + t.rank = static_cast(-1); + if (mark == utility::string_t::npos) + { + t.length = encoding.size() - n; + n = utility::string_t::npos; + } + else + { + t.length = mark - n; + n = mark + 1; + } + + // Then remove leading and trailing whitespace + remove_surrounding_http_whitespace(encoding, t.start, t.length); + + // Next split at the semicolon, if any, and deal with rank and additional whitespace + mark = encoding.find(_XPLATSTR(";")[0], t.start); + if (mark < t.start + t.length) + { + end = t.start + t.length - 1; + t.length = mark - t.start; + while (t.length > 0 && is_http_whitespace(encoding.at(t.start + t.length - 1))) + { + // Skip trailing whitespace in encoding type + t.length--; + } + if (mark < end) + { + // Check for an optional ranking, max. length "q=0.999" + mark = encoding.find(_XPLATSTR("q="), mark + 1); + if (mark != utility::string_t::npos && mark + 1 < end && end - mark <= 6) + { + // Determine ranking; leading whitespace has been implicitly skipped by find(). + // The ranking always starts with '1' or '0' per standard, and has at most 3 decimal places + mark += 1; + t.rank = 1000 * (encoding.at(mark + 1) - _XPLATSTR("0")[0]); + if (mark + 2 < end && encoding.at(mark + 2) == _XPLATSTR(".")[0]) + { + // This is a real number rank; convert decimal part to hundreds and apply it + size_t factor = 100; + mark += 2; + for (size_t i = mark + 1; i <= end; i++) + { + t.rank += (encoding.at(i) - _XPLATSTR("0")[0]) * factor; + factor /= 10; + } + } + if (t.rank > 1000) + { + throw http_exception(status_codes::BadRequest, "Invalid q-value in header"); + } + } + } + } + + if (!t.length) + { + if (!first || n != utility::string_t::npos) + { + // An entirely empty header is OK per RFC, but an extraneous comma is not + throw http_exception(status_codes::BadRequest, "Empty field in header"); + } + return std::unique_ptr(); + } + + if (!compressor) + { + if (t.rank == static_cast(1000) || t.rank == static_cast(-1)) + { + // Immediately try to instantiate a compressor for any unranked or top-ranked algorithm + compressor = web::http::compression::builtin::_make_compressor(f, encoding.substr(t.start, t.length)); + } + else if (t.rank) + { + // Store off remaining ranked algorithms, sorting as we go + if (t.rank >= highest) + { + tokens.emplace_back(t); + highest = t.rank; + } + else + { + for (auto x = tokens.begin(); x != tokens.end(); x++) + { + if (t.rank <= x->rank) + { + tokens.emplace(x, t); + break; + } + } + } + } + // else a rank of 0 means "not permitted" + } + // else we've chosen a compressor; we're just validating the rest of the header + + first = false; + } + // Note: for Accept-Encoding, we don't currently explicitly handle "identity;q=0" and "*;q=0" + + if (compressor) + { + return std::move(compressor); + } + + // If we're here, we didn't match the caller's compressor above; + // try any that we saved off in order of highest to lowest rank + for (auto t = tokens.rbegin(); t != tokens.rend(); t++) + { + auto coding = encoding.substr(t->start, t->length); + + // N.B for TE, "trailers" will simply fail to instantiate a + // compressor; ditto for "*" and "identity" for Accept-Encoding + auto compressor = web::http::compression::builtin::_make_compressor(f, coding); + if (compressor) + { + return std::move(compressor); + } + if (type == header_types::accept_encoding && utility::details::str_iequal(coding, _XPLATSTR("identity"))) + { + // The client specified a preference for "no encoding" vs. anything else we might still have + return std::unique_ptr(); + } + } + + return std::unique_ptr(); +} + +std::unique_ptr get_decompressor_from_header( + const utility::string_t& encoding, + header_types type, + const std::vector>& factories) +{ + const std::vector>& f = + factories.empty() ? web::http::compression::builtin::g_decompress_factories : factories; + std::unique_ptr decompressor; + utility::string_t token; + size_t start; + size_t length; + size_t comma; + size_t n; + + _ASSERTE(type == header_types::transfer_encoding || type == header_types::content_encoding); + + n = 0; + while (n != utility::string_t::npos) + { + // Tokenize by commas first + comma = encoding.find(_XPLATSTR(","), n); + start = n; + if (comma == utility::string_t::npos) + { + length = encoding.size() - n; + n = utility::string_t::npos; + } + else + { + length = comma - n; + n = comma + 1; + } + + // Then remove leading and trailing whitespace + remove_surrounding_http_whitespace(encoding, start, length); + + if (!length) + { + throw http_exception(status_codes::BadRequest, "Empty field in header"); + } + + // Immediately try to instantiate a decompressor + token = encoding.substr(start, length); + auto d = web::http::compression::builtin::_make_decompressor(f, token); + if (d) + { + if (decompressor) + { + status_code code = status_codes::NotImplemented; + if (type == header_types::content_encoding) + { + code = status_codes::UnsupportedMediaType; + } + throw http_exception(code, "Multiple compression algorithms not supported for a single request"); + } + + // We found our decompressor; store it off while we process the rest of the header + decompressor = std::move(d); + } + else + { + if (n != utility::string_t::npos) + { + if (type == header_types::transfer_encoding && + utility::details::str_iequal(_XPLATSTR("chunked"), token)) + { + throw http_exception(status_codes::BadRequest, + "Chunked must come last in the Transfer-Encoding header"); + } + } + if (!decompressor && !f.empty() && (n != utility::string_t::npos || type == header_types::content_encoding)) + { + // The first encoding type did not match; throw an informative + // exception with an encoding-type-appropriate HTTP error code + status_code code = status_codes::NotImplemented; + if (type == header_types::content_encoding) + { + code = status_codes::UnsupportedMediaType; + } + throw http_exception(code, "Unsupported encoding type"); + } + } + } + + if (type == header_types::transfer_encoding && !utility::details::str_iequal(_XPLATSTR("chunked"), token)) + { + throw http_exception(status_codes::BadRequest, "Transfer-Encoding header missing chunked"); + } + + // Either the response is compressed and we have a decompressor that can handle it, or + // built-in compression is not enabled and we don't have an alternate set of decompressors + return std::move(decompressor); +} + +utility::string_t build_supported_header(header_types type, + const std::vector>& factories) +{ + const std::vector>& f = + factories.empty() ? web::http::compression::builtin::g_decompress_factories : factories; + utility::ostringstream_t os; + bool start; + + _ASSERTE(type == header_types::te || type == header_types::accept_encoding); + + // Add all specified algorithms and their weights to the header + start = true; + for (int i = 0; i < f.size(); i++) + { + auto factory = f[i].get(); + if (factory) + { + auto weight = factory->weight(); + + if (!start) + { + os << _XPLATSTR(", "); + } + os << factory->algorithm(); + if (weight <= 1000) + { + os << _XPLATSTR(";q=") << weight / 1000 << _XPLATSTR(".") << weight % 1000; + } + start = false; + } + } + + if (start && type == header_types::accept_encoding) + { + // Request that no encoding be applied + os << _XPLATSTR("identity;q=1, *;q=0"); + } + + return std::move(os.str()); +} +} // namespace details +} // namespace compression +} // namespace http +} // namespace web diff --git a/Release/src/http/common/http_helpers.cpp b/Release/src/http/common/http_helpers.cpp index 2c45e5961d..0d17c569eb 100644 --- a/Release/src/http/common/http_helpers.cpp +++ b/Release/src/http/common/http_helpers.cpp @@ -12,27 +12,6 @@ ****/ #include "stdafx.h" - -// CPPREST_EXCLUDE_COMPRESSION is set if we're on a platform that supports compression but we want to explicitly disable it. -// CPPREST_EXCLUDE_WEBSOCKETS is a flag that now essentially means "no external dependencies". TODO: Rename - -#if __APPLE__ -#include "TargetConditionals.h" -#if defined(TARGET_OS_MAC) -#if !defined(CPPREST_EXCLUDE_COMPRESSION) -#define CPPREST_HTTP_COMPRESSION -#endif // !defined(CPPREST_EXCLUDE_COMPRESSION) -#endif // defined(TARGET_OS_MAC) -#elif defined(_WIN32) && (!defined(WINAPI_FAMILY) || WINAPI_PARTITION_DESKTOP) -#if !defined(CPPREST_EXCLUDE_WEBSOCKETS) && !defined(CPPREST_EXCLUDE_COMPRESSION) -#define CPPREST_HTTP_COMPRESSION -#endif // !defined(CPPREST_EXCLUDE_WEBSOCKETS) && !defined(CPPREST_EXCLUDE_COMPRESSION) -#endif - -#if defined(CPPREST_HTTP_COMPRESSION) -#include -#endif - #include "internal_http_helpers.h" using namespace web; @@ -142,309 +121,5 @@ bool validate_method(const utility::string_t& method) return true; } -namespace compression -{ -#if defined(CPPREST_HTTP_COMPRESSION) - - class compression_base_impl - { - public: - compression_base_impl(compression_algorithm alg) : m_alg(alg), m_zLibState(Z_OK) - { - memset(&m_zLibStream, 0, sizeof(m_zLibStream)); - } - - size_t read_output(size_t input_offset, size_t available_input, size_t total_out_before, uint8_t* temp_buffer, data_buffer& output) - { - input_offset += (available_input - stream().avail_in); - auto out_length = stream().total_out - total_out_before; - output.insert(output.end(), temp_buffer, temp_buffer + out_length); - - return input_offset; - } - - bool is_complete() const - { - return state() == Z_STREAM_END; - } - - bool has_error() const - { - return !is_complete() && state() != Z_OK; - } - - int state() const - { - return m_zLibState; - } - - void set_state(int state) - { - m_zLibState = state; - } - - compression_algorithm algorithm() const - { - return m_alg; - } - - z_stream& stream() - { - return m_zLibStream; - } - - int to_zlib_alg(compression_algorithm alg) - { - return static_cast(alg); - } - - private: - const compression_algorithm m_alg; - - std::atomic m_zLibState{ Z_OK }; - z_stream m_zLibStream; - }; - - class stream_decompressor::stream_decompressor_impl : public compression_base_impl - { - public: - stream_decompressor_impl(compression_algorithm alg) : compression_base_impl(alg) - { - set_state(inflateInit2(&stream(), to_zlib_alg(alg))); - } - - ~stream_decompressor_impl() - { - inflateEnd(&stream()); - } - - data_buffer decompress(const uint8_t* input, size_t input_size) - { - if (input == nullptr || input_size == 0) - { - set_state(Z_BUF_ERROR); - return data_buffer(); - } - - // Need to guard against attempting to decompress when we're already finished or encountered an error! - if (is_complete() || has_error()) - { - set_state(Z_STREAM_ERROR); - return data_buffer(); - } - - const size_t BUFFER_SIZE = 1024; - unsigned char temp_buffer[BUFFER_SIZE]; - - data_buffer output; - output.reserve(input_size * 3); - - size_t input_offset{ 0 }; - - while (state() == Z_OK && input_offset < input_size) - { - auto total_out_before = stream().total_out; - - auto available_input = input_size - input_offset; - stream().next_in = const_cast(&input[input_offset]); - stream().avail_in = static_cast(available_input); - stream().next_out = temp_buffer; - stream().avail_out = BUFFER_SIZE; - - set_state(inflate(&stream(), Z_PARTIAL_FLUSH)); - - if (has_error()) - { - return data_buffer(); - } - - input_offset = read_output(input_offset, available_input, total_out_before, temp_buffer, output); - } - - return output; - } - }; - - class stream_compressor::stream_compressor_impl : public compression_base_impl - { - public: - stream_compressor_impl(compression_algorithm alg) : compression_base_impl(alg) - { - const int level = Z_DEFAULT_COMPRESSION; - if (alg == compression_algorithm::gzip) - { - set_state(deflateInit2(&stream(), level, Z_DEFLATED, to_zlib_alg(alg), MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY)); - } - else if (alg == compression_algorithm::deflate) - { - set_state(deflateInit(&stream(), level)); - } - } - - web::http::details::compression::data_buffer compress(const uint8_t* input, size_t input_size, bool finish) - { - if (input == nullptr || input_size == 0) - { - set_state(Z_BUF_ERROR); - return data_buffer(); - } - - if (state() != Z_OK) - { - set_state(Z_STREAM_ERROR); - return data_buffer(); - } - - data_buffer output; - output.reserve(input_size); - - const size_t BUFFER_SIZE = 1024; - uint8_t temp_buffer[BUFFER_SIZE]; - - size_t input_offset{ 0 }; - auto flush = Z_NO_FLUSH; - - while (flush == Z_NO_FLUSH) - { - auto total_out_before = stream().total_out; - auto available_input = input_size - input_offset; - - if (available_input == 0) - { - flush = finish ? Z_FINISH : Z_PARTIAL_FLUSH; - } - else - { - stream().avail_in = static_cast(available_input); - stream().next_in = const_cast(&input[input_offset]); - } - - do - { - stream().next_out = temp_buffer; - stream().avail_out = BUFFER_SIZE; - - set_state(deflate(&stream(), flush)); - - if (has_error()) - { - return data_buffer(); - } - - input_offset = read_output(input_offset, available_input, total_out_before, temp_buffer, output); - - } while (stream().avail_out == 0); - } - - return output; - } - - ~stream_compressor_impl() - { - deflateEnd(&stream()); - } - }; -#else // Stub impl for when compression is not supported - - class compression_base_impl - { - public: - bool has_error() const - { - return true; - } - }; - - class stream_compressor::stream_compressor_impl : public compression_base_impl - { - public: - stream_compressor_impl(compression_algorithm) {} - compression::data_buffer compress(const uint8_t* data, size_t size, bool) - { - return data_buffer(data, data + size); - } - }; - - class stream_decompressor::stream_decompressor_impl : public compression_base_impl - { - public: - stream_decompressor_impl(compression_algorithm) {} - compression::data_buffer decompress(const uint8_t* data, size_t size) - { - return data_buffer(data, data + size); - } - }; -#endif - - bool __cdecl stream_decompressor::is_supported() - { -#if !defined(CPPREST_HTTP_COMPRESSION) - return false; -#else - return true; -#endif - } - - stream_decompressor::stream_decompressor(compression_algorithm alg) - : m_pimpl(std::make_shared(alg)) - { - } - - compression::data_buffer stream_decompressor::decompress(const data_buffer& input) - { - if (input.empty()) - { - return data_buffer(); - } - - return m_pimpl->decompress(&input[0], input.size()); - } - - web::http::details::compression::data_buffer stream_decompressor::decompress(const uint8_t* input, size_t input_size) - { - return m_pimpl->decompress(input, input_size); - } - - bool stream_decompressor::has_error() const - { - return m_pimpl->has_error(); - } - - bool __cdecl stream_compressor::is_supported() - { -#if !defined(CPPREST_HTTP_COMPRESSION) - return false; -#else - return true; -#endif - } - - stream_compressor::stream_compressor(compression_algorithm alg) - : m_pimpl(std::make_shared(alg)) - { - - } - - compression::data_buffer stream_compressor::compress(const data_buffer& input, bool finish) - { - if (input.empty()) - { - return compression::data_buffer(); - } - - return m_pimpl->compress(&input[0], input.size(), finish); - } - - web::http::details::compression::data_buffer stream_compressor::compress(const uint8_t* input, size_t input_size, bool finish) - { - return m_pimpl->compress(input, input_size, finish); - } - - bool stream_compressor::has_error() const - { - return m_pimpl->has_error(); - } - -} // namespace compression } // namespace details }} // namespace web::http diff --git a/Release/src/http/common/http_msg.cpp b/Release/src/http/common/http_msg.cpp index 8f218cb913..d17d09dcef 100644 --- a/Release/src/http/common/http_msg.cpp +++ b/Release/src/http/common/http_msg.cpp @@ -310,36 +310,95 @@ void http_msg_base::_prepare_to_receive_data() // or media (like file) that the user can read from... } -size_t http_msg_base::_get_content_length() +size_t http_msg_base::_get_stream_length() +{ + auto &stream = instream(); + + if (stream.can_seek()) + { + auto offset = stream.tell(); + auto end = stream.seek(0, std::ios_base::end); + stream.seek(offset); + return static_cast(end - offset); + } + + return std::numeric_limits::max(); +} + +size_t http_msg_base::_get_content_length(bool honor_compression) { // An invalid response_stream indicates that there is no body if ((bool)instream()) { - size_t content_length = 0; + size_t content_length; utility::string_t transfer_encoding; - bool has_cnt_length = headers().match(header_names::content_length, content_length); - bool has_xfr_encode = headers().match(header_names::transfer_encoding, transfer_encoding); + if (headers().match(header_names::transfer_encoding, transfer_encoding)) + { + // Transfer encoding is set; it trumps any content length that may or may not be present + if (honor_compression && m_compressor) + { + http::http_headers tmp; + + // Build a header for comparison with the existing one + tmp.add(header_names::transfer_encoding, m_compressor->algorithm()); + tmp.add(header_names::transfer_encoding, _XPLATSTR("chunked")); + + if (!utility::details::str_iequal(transfer_encoding, tmp[header_names::transfer_encoding])) + { + // Some external entity added this header, and it doesn't match our + // expectations; bail out, since the caller's intentions are not clear + throw http_exception("Transfer-Encoding header is internally managed when compressing"); + } + } - if (has_xfr_encode) + return std::numeric_limits::max(); + } + + if (honor_compression && m_compressor) { + // A compressor is set; this implies transfer encoding, since we don't know the compressed length + // up front for content encoding. We return the uncompressed length if we can figure it out. + headers().add(header_names::transfer_encoding, m_compressor->algorithm()); + headers().add(header_names::transfer_encoding, _XPLATSTR("chunked")); return std::numeric_limits::max(); } - if (has_cnt_length) + if (headers().match(header_names::content_length, content_length)) + { + // An explicit content length is set; trust it, since we + // may not be required to send the stream's entire contents + return content_length; + } + + content_length = _get_stream_length(); + if (content_length != std::numeric_limits::max()) { + // The content length wasn't explcitly set, but we figured it out; + // use it, since sending this way is more efficient than chunking + headers().add(header_names::content_length, content_length); return content_length; } - // Neither is set. Assume transfer-encoding for now (until we have the ability to determine - // the length of the stream). + // We don't know the content length; we'll chunk the stream headers().add(header_names::transfer_encoding, _XPLATSTR("chunked")); return std::numeric_limits::max(); } + // There is no content return 0; } +size_t http_msg_base::_get_content_length_and_set_compression() +{ + return _get_content_length(true); +} + +size_t http_msg_base::_get_content_length() +{ + return _get_content_length(false); +} + // Helper function to inline continuation if possible. struct inline_continuation { @@ -1041,6 +1100,11 @@ details::_http_request::_http_request(std::unique_ptrset_decompress_factories(compression::details::builtin::get_decompress_factories()); +} + const http_version http_versions::HTTP_0_9 = { 0, 9 }; const http_version http_versions::HTTP_1_0 = { 1, 0 }; const http_version http_versions::HTTP_1_1 = { 1, 1 }; diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp index 8da74d0083..3adb4fb882 100644 --- a/Release/src/http/listener/http_server_httpsys.cpp +++ b/Release/src/http/listener/http_server_httpsys.cpp @@ -85,7 +85,7 @@ static utility::string_t HttpServerAPIKnownHeaders[] = U("Proxy-Authorization"), U("Referer"), U("Range"), - U("Te"), + U("TE"), U("Translate"), U("User-Agent"), U("Request-Maximum"), @@ -539,6 +539,7 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD } else { + utility::string_t header; std::string badRequestMsg; try { @@ -557,6 +558,66 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD m_msg.set_method(parse_request_method(m_request)); parse_http_headers(m_request->Headers, m_msg.headers()); + // See if we need to compress or decompress the incoming request body, and if so, prepare for it + try + { + if (m_msg.headers().match(header_names::transfer_encoding, header)) + { + try + { + m_decompressor = http::compression::details::get_decompressor_from_header(header, http::compression::details::header_types::transfer_encoding); + } + catch (http_exception &e) + { + if (e.error_code().value() != status_codes::NotImplemented) + { + // Something is wrong with the header; we'll fail here + throw; + } + // We could not find a decompressor; we'll see if the user's handler adds one later + m_decompress_header_type = http::compression::details::header_types::transfer_encoding; + m_decompress_header = std::move(header); + } + } + else if (m_msg.headers().match(header_names::content_encoding, header)) + { + try + { + m_decompressor = http::compression::details::get_decompressor_from_header(header, http::compression::details::header_types::content_encoding); + } + catch (http_exception &e) + { + if (e.error_code().value() != status_codes::UnsupportedMediaType) + { + // Something is wrong with the header; we'll fail here + throw; + } + // We could not find a decompressor; we'll see if the user's handler adds one later + m_decompress_header_type = http::compression::details::header_types::content_encoding; + m_decompress_header = std::move(header); + } + } + else if (m_msg.headers().match(header_names::te, header)) + { + // Note that init_response_headers throws away m_msg, so we need to set our compressor here. If + // the header contains all unsupported algorithms, it's not an error -- we just won't compress + m_compressor = http::compression::details::get_compressor_from_header(header, http::compression::details::header_types::te); + } + else if (m_msg.headers().match(header_names::accept_encoding, header)) + { + // This would require pre-compression of the input stream, since we MUST send Content-Length, so we'll (legally) ignore it + //m_compressor = http::compression::details::get_compressor_from_header(header, http::compression::details::header_types:accept_encoding); + } + } + catch (http_exception &e) + { + if (badRequestMsg.empty()) + { + // Respond with a reasonable message + badRequestMsg = e.what(); + } + } + m_msg._get_impl()->_set_http_version({ (uint8_t)m_request->Version.MajorVersion, (uint8_t)m_request->Version.MinorVersion }); // Retrieve the remote IP address @@ -601,12 +662,24 @@ void windows_request_context::read_headers_io_completion(DWORD error_code, DWORD void windows_request_context::read_request_body_chunk() { auto *pServer = static_cast(http_server_api::server_api()); + PVOID body; // The read_body_io_completion callback function m_overlapped.set_http_io_completion([this](DWORD error, DWORD nBytes){ read_body_io_completion(error, nBytes);}); auto request_body_buf = m_msg._get_impl()->outstream().streambuf(); - auto body = request_body_buf.alloc(CHUNK_SIZE); + if (!m_decompressor) + { + body = request_body_buf.alloc(CHUNK_SIZE); + } + else + { + if (m_compress_buffer.size() < CHUNK_SIZE) + { + m_compress_buffer.resize(CHUNK_SIZE); + } + body = m_compress_buffer.data(); + } // Once we allow users to set the output stream the following assert could fail. // At that time we would need compensation code that would allocate a buffer from the heap instead. @@ -626,7 +699,10 @@ void windows_request_context::read_request_body_chunk() { // There was no more data to read. CancelThreadpoolIo(pServer->m_threadpool_io); - request_body_buf.commit(0); + if (!m_decompressor) + { + request_body_buf.commit(0); + } if(error_code == ERROR_HANDLE_EOF) { m_msg._get_impl()->_complete(request_body_buf.in_avail()); @@ -647,17 +723,49 @@ void windows_request_context::read_body_io_completion(DWORD error_code, DWORD by if (error_code == NO_ERROR) { - request_body_buf.commit(bytes_read); + if (!m_decompressor) + { + request_body_buf.commit(bytes_read); + } + else + { + size_t got; + size_t used; + size_t total_used = 0; + + do + { + auto body = request_body_buf.alloc(CHUNK_SIZE); + try + { + got = m_decompressor->decompress(m_compress_buffer.data()+total_used, bytes_read-total_used, body, CHUNK_SIZE, http::compression::operation_hint::has_more, used, NULL); + } + catch (...) + { + request_body_buf.commit(0); + m_msg._get_impl()->_complete(0, std::current_exception()); + return; + } + request_body_buf.commit(got); + total_used += used; + } while (total_used != bytes_read); + } read_request_body_chunk(); } else if (error_code == ERROR_HANDLE_EOF) { - request_body_buf.commit(0); + if (!m_decompressor) + { + request_body_buf.commit(0); + } m_msg._get_impl()->_complete(request_body_buf.in_avail()); } else { - request_body_buf.commit(0); + if (!m_decompressor) + { + request_body_buf.commit(0); + } m_msg._get_impl()->_complete(0, std::make_exception_ptr(http_exception(error_code))); } } @@ -800,8 +908,53 @@ void windows_request_context::async_process_response() const std::string reason = utf16_to_utf8(m_response.reason_phrase()); win_api_response.pReason = reason.c_str(); win_api_response.ReasonLength = (USHORT)reason.size(); + size_t content_length; - size_t content_length = m_response._get_impl()->_get_content_length(); + if (m_compressor || m_response._get_impl()->compressor()) + { + if (m_response.headers().has(header_names::content_length)) + { + // Content-Length should not be sent with Transfer-Encoding + m_response.headers().remove(header_names::content_length); + } + if (!m_response._get_impl()->compressor()) + { + // Temporarily move the compressor to the reponse, so _get_content_length() will honor it + m_response._get_impl()->set_compressor(std::move(m_compressor)); + } // else one was already set from a callback, and we'll (blindly) use it + content_length = m_response._get_impl()->_get_content_length_and_set_compression(); + m_compressor = std::move(m_response._get_impl()->compressor()); + m_response._get_impl()->set_compressor(nullptr); + } + else + { + if (!m_decompress_header.empty()) + { + auto factories = m_response._get_impl()->decompress_factories(); + try + { + m_decompressor = http::compression::details::get_decompressor_from_header(m_decompress_header, m_decompress_header_type, factories); + m_decompress_header.clear(); + if (!m_decompressor) + { + http::status_code code = http::status_codes::NotImplemented; + if (m_decompress_header_type == http::compression::details::header_types::content_encoding) + { + code = status_codes::UnsupportedMediaType; + } + throw http_exception(code); + } + } + catch (http_exception &e) + { + // No matching decompressor was supplied via callback + CancelThreadpoolIo(pServer->m_threadpool_io); + cancel_request(std::make_exception_ptr(e)); + return; + } + } + content_length = m_response._get_impl()->_get_content_length(); + } m_headers = std::unique_ptr(new HTTP_UNKNOWN_HEADER[msl::safeint3::SafeInt(m_response.headers().size())]); m_headers_buffer.resize(msl::safeint3::SafeInt(m_response.headers().size()) * 2); @@ -822,8 +975,6 @@ void windows_request_context::async_process_response() // Send response callback function m_overlapped.set_http_io_completion([this](DWORD error, DWORD nBytes){ send_response_io_completion(error, nBytes);}); - m_remaining_to_write = content_length; - // Figure out how to send the entity body of the message. if (content_length == 0) { @@ -854,6 +1005,12 @@ void windows_request_context::async_process_response() _ASSERTE(content_length > 0); m_sending_in_chunks = (content_length != std::numeric_limits::max()); m_transfer_encoding = (content_length == std::numeric_limits::max()); + m_remaining_to_write = content_length; + if (content_length == std::numeric_limits::max()) + { + // Attempt to figure out the remaining length of the input stream + m_remaining_to_write = m_response._get_impl()->_get_stream_length(); + } StartThreadpoolIo(pServer->m_threadpool_io); const unsigned long error_code = HttpSendHttpResponse( @@ -901,11 +1058,12 @@ void windows_request_context::transmit_body() return; } + msl::safeint3::SafeInt safeCount = m_remaining_to_write; + size_t next_chunk_size = safeCount.Min(CHUNK_SIZE); + // In both cases here we could perform optimizations to try and use acquire on the streams to avoid an extra copy. if ( m_sending_in_chunks ) { - msl::safeint3::SafeInt safeCount = m_remaining_to_write; - size_t next_chunk_size = safeCount.Min(CHUNK_SIZE); m_body_data.resize(CHUNK_SIZE); streams::rawptr_buffer buf(&m_body_data[0], next_chunk_size); @@ -937,33 +1095,109 @@ void windows_request_context::transmit_body() else { // We're transfer-encoding... - const size_t body_data_length = CHUNK_SIZE+http::details::chunked_encoding::additional_encoding_space; - m_body_data.resize(body_data_length); - - streams::rawptr_buffer buf(&m_body_data[http::details::chunked_encoding::data_offset], body_data_length); - - m_response.body().read(buf, CHUNK_SIZE).then([this, body_data_length](pplx::task op) + if (m_compressor) { - size_t bytes_read = 0; + // ...and compressing. For simplicity, we allocate a buffer that's "too large to fail" while compressing. + const size_t body_data_length = 2*CHUNK_SIZE + http::details::chunked_encoding::additional_encoding_space; + m_body_data.resize(body_data_length); - // If an exception occurs surface the error to user on the server side - // and cancel the request so the client sees the error. - try - { - bytes_read = op.get(); - } catch (...) + // We'll read into a temporary buffer before compressing + if (m_compress_buffer.capacity() < next_chunk_size) { - cancel_request(std::current_exception()); - return; + m_compress_buffer.reserve(next_chunk_size); } - // Check whether this is the last one to send... - m_transfer_encoding = (bytes_read > 0); - size_t offset = http::details::chunked_encoding::add_chunked_delimiters(&m_body_data[0], body_data_length, bytes_read); + streams::rawptr_buffer buf(m_compress_buffer.data(), next_chunk_size); - auto data_length = bytes_read + (http::details::chunked_encoding::additional_encoding_space-offset); - send_entity_body(&m_body_data[offset], data_length); - }); + m_response.body().read(buf, next_chunk_size).then([this, body_data_length](pplx::task op) + { + size_t bytes_read = 0; + + // If an exception occurs surface the error to user on the server side + // and cancel the request so the client sees the error. + try + { + bytes_read = op.get(); + } + catch (...) + { + cancel_request(std::current_exception()); + return; + } + _ASSERTE(bytes_read >= 0); + + // Compress this chunk; if we read no data, allow the compressor to finalize its stream + http::compression::operation_hint hint = http::compression::operation_hint::has_more; + if (!bytes_read) + { + hint = http::compression::operation_hint::is_last; + } + m_compressor->compress(m_compress_buffer.data(), bytes_read, &m_body_data[http::details::chunked_encoding::data_offset], body_data_length, hint) + .then([this, bytes_read, body_data_length](pplx::task op) + { + http::compression::operation_result r; + + try + { + r = op.get(); + } + catch (...) + { + cancel_request(std::current_exception()); + return; + } + + if (r.input_bytes_processed != bytes_read || + r.output_bytes_produced == body_data_length - http::details::chunked_encoding::additional_encoding_space || + r.done != !bytes_read) + { + // We chose our parameters so that compression should + // never overflow body_data_length; fail if it does + cancel_request(std::make_exception_ptr(std::exception("Compressed data exceeds internal buffer size."))); + return; + } + + // Check whether this is the last one to send; note that this is a + // few lines of near-duplicate code with the non-compression path + _ASSERTE(bytes_read <= m_remaining_to_write); + m_remaining_to_write -= bytes_read; + m_transfer_encoding = (r.output_bytes_produced > 0); + size_t offset = http::details::chunked_encoding::add_chunked_delimiters(&m_body_data[0], body_data_length, r.output_bytes_produced); + send_entity_body(&m_body_data[offset], r.output_bytes_produced + http::details::chunked_encoding::additional_encoding_space - offset); + }); + }); + } + else + { + const size_t body_data_length = CHUNK_SIZE + http::details::chunked_encoding::additional_encoding_space; + m_body_data.resize(body_data_length); + + streams::rawptr_buffer buf(&m_body_data[http::details::chunked_encoding::data_offset], body_data_length); + + m_response.body().read(buf, next_chunk_size).then([this, body_data_length](pplx::task op) + { + size_t bytes_read = 0; + + // If an exception occurs surface the error to user on the server side + // and cancel the request so the client sees the error. + try + { + bytes_read = op.get(); + } + catch (...) + { + cancel_request(std::current_exception()); + return; + } + + // Check whether this is the last one to send... + m_transfer_encoding = (bytes_read > 0); + size_t offset = http::details::chunked_encoding::add_chunked_delimiters(&m_body_data[0], body_data_length, bytes_read); + + auto data_length = bytes_read + (http::details::chunked_encoding::additional_encoding_space - offset); + send_entity_body(&m_body_data[offset], data_length); + }); + } } } diff --git a/Release/src/http/listener/http_server_httpsys.h b/Release/src/http/listener/http_server_httpsys.h index 2523d62e4e..5a8cbd137b 100644 --- a/Release/src/http/listener/http_server_httpsys.h +++ b/Release/src/http/listener/http_server_httpsys.h @@ -143,6 +143,13 @@ struct windows_request_context : http::details::_http_server_context http_response m_response; std::exception_ptr m_except_ptr; + + std::vector m_compress_buffer; + std::unique_ptr m_compressor; + std::unique_ptr m_decompressor; + utility::string_t m_decompress_header; + http::compression::details::header_types m_decompress_header_type; + private: windows_request_context(const windows_request_context &); windows_request_context& operator=(const windows_request_context &); diff --git a/Release/tests/functional/http/client/CMakeLists.txt b/Release/tests/functional/http/client/CMakeLists.txt index 60804e1742..17cf4eff81 100644 --- a/Release/tests/functional/http/client/CMakeLists.txt +++ b/Release/tests/functional/http/client/CMakeLists.txt @@ -21,6 +21,7 @@ set(SOURCES status_code_reason_phrase_tests.cpp to_string_tests.cpp http_client_fuzz_tests.cpp + compression_tests.cpp stdafx.cpp ) diff --git a/Release/tests/functional/http/client/compression_tests.cpp b/Release/tests/functional/http/client/compression_tests.cpp new file mode 100644 index 0000000000..2a49f2263f --- /dev/null +++ b/Release/tests/functional/http/client/compression_tests.cpp @@ -0,0 +1,1401 @@ +/*** + * Copyright (C) Microsoft. All rights reserved. + * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. + * + * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * + * compression_tests.cpp + * + * Tests cases, including client/server, for the web::http::compression namespace. + * + * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + ****/ + +#include "cpprest/details/http_helpers.h" +#include "cpprest/version.h" +#include "stdafx.h" +#include + +#ifndef __cplusplus_winrt +#include "cpprest/http_listener.h" +#endif + +using namespace web; +using namespace utility; +using namespace web::http; +using namespace web::http::client; + +using namespace tests::functional::http::utilities; + +namespace tests +{ +namespace functional +{ +namespace http +{ +namespace client +{ +SUITE(compression_tests) +{ + // A fake "pass-through" compressor/decompressor for testing + class fake_provider : public web::http::compression::compress_provider, + public web::http::compression::decompress_provider + { + public: + static const utility::string_t FAKE; + + fake_provider(size_t size = static_cast(-1)) : _size(size), _so_far(0), _done(false) {} + + virtual const utility::string_t& algorithm() const { return FAKE; } + + virtual size_t decompress(const uint8_t* input, + size_t input_size, + uint8_t* output, + size_t output_size, + web::http::compression::operation_hint hint, + size_t& input_bytes_processed, + bool* done) + { + size_t bytes; + + if (_done) + { + input_bytes_processed = 0; + if (*done) + { + *done = true; + } + return 0; + } + if (_size == static_cast(-1) || input_size > _size - _so_far) + { + std::stringstream ss; + ss << "Fake decompress - invalid data " << input_size << ", " << output_size << " with " << _so_far + << " / " << _size; + throw std::runtime_error(std::move(ss.str())); + } + bytes = std::min(input_size, output_size); + if (bytes) + { + memcpy(output, input, bytes); + } + _so_far += bytes; + _done = (_so_far == _size); + if (done) + { + *done = _done; + } + input_bytes_processed = bytes; + return input_bytes_processed; + } + + virtual pplx::task decompress( + const uint8_t* input, + size_t input_size, + uint8_t* output, + size_t output_size, + web::http::compression::operation_hint hint) + { + web::http::compression::operation_result r; + + try + { + r.output_bytes_produced = + decompress(input, input_size, output, output_size, hint, r.input_bytes_processed, &r.done); + } + catch (...) + { + pplx::task_completion_event ev; + ev.set_exception(std::current_exception()); + return pplx::create_task(ev); + } + + return pplx::task_from_result(r); + } + + virtual size_t compress(const uint8_t* input, + size_t input_size, + uint8_t* output, + size_t output_size, + web::http::compression::operation_hint hint, + size_t& input_bytes_processed, + bool* done) + { + size_t bytes; + + if (_done) + { + input_bytes_processed = 0; + if (*done) + { + *done = true; + } + return 0; + } + if (_size == static_cast(-1) || input_size > _size - _so_far) + { + std::stringstream ss; + ss << "Fake compress - invalid data " << input_size << ", " << output_size << " with " << _so_far + << " / " << _size; + throw std::runtime_error(std::move(ss.str())); + } + bytes = std::min(input_size, output_size); + if (bytes) + { + memcpy(output, input, bytes); + } + _so_far += bytes; + _done = (hint == web::http::compression::operation_hint::is_last && _so_far == _size); + if (done) + { + *done = _done; + } + input_bytes_processed = bytes; + return input_bytes_processed; + } + + virtual pplx::task compress( + const uint8_t* input, + size_t input_size, + uint8_t* output, + size_t output_size, + web::http::compression::operation_hint hint) + { + web::http::compression::operation_result r; + + try + { + r.output_bytes_produced = + compress(input, input_size, output, output_size, hint, r.input_bytes_processed, &r.done); + } + catch (...) + { + pplx::task_completion_event ev; + ev.set_exception(std::current_exception()); + return pplx::create_task(ev); + } + + return pplx::task_from_result(r); + } + + virtual void reset() + { + _done = false; + _so_far = 0; + } + + private: + size_t _size; + size_t _so_far; + bool _done; + }; + + const utility::string_t fake_provider::FAKE = _XPLATSTR("fake"); + + void compress_and_decompress( + const utility::string_t& algorithm, const size_t buffer_size, const size_t chunk_size, bool compressible) + { + std::unique_ptr compressor; + std::unique_ptr decompressor; + std::vector input_buffer; + std::vector cmp_buffer; + std::vector dcmp_buffer; + web::http::compression::operation_result r; + std::vector chunk_sizes; + Concurrency::task_group_status result; + size_t csize; + size_t dsize; + size_t i; + size_t nn; + + if (algorithm == fake_provider::FAKE) + { + compressor = std::make_unique(buffer_size); + decompressor = std::make_unique(buffer_size); + } + else + { + compressor = web::http::compression::builtin::make_compressor(algorithm); + decompressor = web::http::compression::builtin::make_decompressor(algorithm); + } + VERIFY_IS_TRUE((bool)compressor); + VERIFY_IS_TRUE((bool)decompressor); + + input_buffer.reserve(buffer_size); + for (size_t i = 0; i < buffer_size; ++i) + { + if (compressible) + { + input_buffer.push_back(static_cast('a' + i % 26)); + } + else + { + input_buffer.push_back(static_cast(std::rand())); + } + } + + // compress in chunks + csize = 0; + cmp_buffer.resize(buffer_size); // pessimistic (or not, for non-compressible data) + for (i = 0; i < buffer_size; i += chunk_size) + { + result = compressor + ->compress(input_buffer.data() + i, + std::min(chunk_size, buffer_size - i), + cmp_buffer.data() + csize, + std::min(chunk_size, buffer_size - csize), + web::http::compression::operation_hint::has_more) + .then([&r](web::http::compression::operation_result x) { r = x; }) + .wait(); + VERIFY_ARE_EQUAL(result, Concurrency::task_group_status::completed); + VERIFY_ARE_EQUAL(r.input_bytes_processed, std::min(chunk_size, buffer_size - i)); + VERIFY_ARE_EQUAL(r.done, false); + chunk_sizes.push_back(r.output_bytes_produced); + csize += r.output_bytes_produced; + } + if (i >= buffer_size) + { + size_t cmpsize = buffer_size; + do + { + if (csize == cmpsize) + { + // extend the output buffer if there may be more compressed bytes to retrieve + cmpsize += std::min(chunk_size, (size_t)200); + cmp_buffer.resize(cmpsize); + } + result = compressor + ->compress(NULL, + 0, + cmp_buffer.data() + csize, + std::min(chunk_size, cmpsize - csize), + web::http::compression::operation_hint::is_last) + .then([&r](web::http::compression::operation_result x) { r = x; }) + .wait(); + VERIFY_ARE_EQUAL(result, Concurrency::task_group_status::completed); + VERIFY_ARE_EQUAL(r.input_bytes_processed, 0); + chunk_sizes.push_back(r.output_bytes_produced); + csize += r.output_bytes_produced; + } while (csize == cmpsize); + VERIFY_ARE_EQUAL(r.done, true); + + // once more with no input, to assure no error and done + result = compressor->compress(NULL, 0, NULL, 0, web::http::compression::operation_hint::is_last) + .then([&r](web::http::compression::operation_result x) { r = x; }) + .wait(); + VERIFY_ARE_EQUAL(result, Concurrency::task_group_status::completed); + VERIFY_ARE_EQUAL(r.input_bytes_processed, 0); + VERIFY_ARE_EQUAL(r.output_bytes_produced, 0); + VERIFY_ARE_EQUAL(r.done, true); + } + cmp_buffer.resize(csize); // actual + + // decompress in as-compressed chunks + nn = 0; + dsize = 0; + dcmp_buffer.resize(buffer_size); + for (std::vector::iterator it = chunk_sizes.begin(); it != chunk_sizes.end(); ++it) + { + if (*it) + { + auto hint = web::http::compression::operation_hint::has_more; + if (it == chunk_sizes.begin()) + { + hint = web::http::compression::operation_hint::is_last; + } + result = decompressor + ->decompress(cmp_buffer.data() + nn, + *it, + dcmp_buffer.data() + dsize, + std::min(chunk_size, buffer_size - dsize), + hint) + .then([&r](web::http::compression::operation_result x) { r = x; }) + .wait(); + VERIFY_ARE_EQUAL(result, Concurrency::task_group_status::completed); + nn += *it; + dsize += r.output_bytes_produced; + } + } + VERIFY_ARE_EQUAL(csize, nn); + VERIFY_ARE_EQUAL(dsize, buffer_size); + VERIFY_ARE_EQUAL(input_buffer, dcmp_buffer); + VERIFY_IS_TRUE(r.done); + + // decompress again in fixed-size chunks + nn = 0; + dsize = 0; + decompressor->reset(); + memset(dcmp_buffer.data(), 0, dcmp_buffer.size()); + do + { + size_t n = std::min(chunk_size, csize - nn); + do + { + result = decompressor + ->decompress(cmp_buffer.data() + nn, + n, + dcmp_buffer.data() + dsize, + std::min(chunk_size, buffer_size - dsize), + web::http::compression::operation_hint::has_more) + .then([&r](web::http::compression::operation_result x) { r = x; }) + .wait(); + VERIFY_ARE_EQUAL(result, Concurrency::task_group_status::completed); + dsize += r.output_bytes_produced; + nn += r.input_bytes_processed; + n -= r.input_bytes_processed; + } while (n); + } while (nn < csize || !r.done); + VERIFY_ARE_EQUAL(csize, nn); + VERIFY_ARE_EQUAL(dsize, buffer_size); + VERIFY_ARE_EQUAL(input_buffer, dcmp_buffer); + VERIFY_IS_TRUE(r.done); + + // once more with no input, to assure no error and done + result = decompressor->decompress(NULL, 0, NULL, 0, web::http::compression::operation_hint::has_more) + .then([&r](web::http::compression::operation_result x) { r = x; }) + .wait(); + VERIFY_ARE_EQUAL(result, Concurrency::task_group_status::completed); + VERIFY_ARE_EQUAL(r.input_bytes_processed, 0); + VERIFY_ARE_EQUAL(r.output_bytes_produced, 0); + VERIFY_IS_TRUE(r.done); + + // decompress all at once + decompressor->reset(); + memset(dcmp_buffer.data(), 0, dcmp_buffer.size()); + result = decompressor + ->decompress(cmp_buffer.data(), + csize, + dcmp_buffer.data(), + dcmp_buffer.size(), + web::http::compression::operation_hint::is_last) + .then([&r](web::http::compression::operation_result x) { r = x; }) + .wait(); + VERIFY_ARE_EQUAL(result, Concurrency::task_group_status::completed); + VERIFY_ARE_EQUAL(r.output_bytes_produced, buffer_size); + VERIFY_ARE_EQUAL(input_buffer, dcmp_buffer); + + if (algorithm != fake_provider::FAKE) + { + // invalid decompress buffer, first and subsequent tries + cmp_buffer[0] = ~cmp_buffer[1]; + decompressor->reset(); + for (i = 0; i < 2; i++) + { + nn = 0; + try + { + result = decompressor + ->decompress(cmp_buffer.data(), + csize, + dcmp_buffer.data(), + dcmp_buffer.size(), + web::http::compression::operation_hint::is_last) + .then([&nn](web::http::compression::operation_result x) { nn++; }) + .wait(); + nn++; + } + catch (std::runtime_error) + { + } + VERIFY_ARE_EQUAL(nn, 0); + } + } + } + + void compress_test(const utility::string_t& algorithm) + { + size_t tuples[][2] = {{7999, 8192}, + {8192, 8192}, + {16001, 8192}, + {16384, 8192}, + {140000, 65536}, + {256 * 1024, 65536}, + {256 * 1024, 256 * 1024}, + {263456, 256 * 1024}}; + + for (int i = 0; i < sizeof(tuples) / sizeof(tuples[0]); i++) + { + for (int j = 0; j < 2; j++) + { + compress_and_decompress(algorithm, tuples[i][0], tuples[i][1], !!j); + } + } + } + + TEST_FIXTURE(uri_address, compress_and_decompress) + { + compress_test(fake_provider::FAKE); + if (web::http::compression::builtin::algorithm::supported(web::http::compression::builtin::algorithm::GZIP)) + { + compress_test(web::http::compression::builtin::algorithm::GZIP); + } + if (web::http::compression::builtin::algorithm::supported(web::http::compression::builtin::algorithm::DEFLATE)) + { + compress_test(web::http::compression::builtin::algorithm::DEFLATE); + } + if (web::http::compression::builtin::algorithm::supported(web::http::compression::builtin::algorithm::BROTLI)) + { + compress_test(web::http::compression::builtin::algorithm::BROTLI); + } + } + + TEST_FIXTURE(uri_address, compress_headers) + { + const utility::string_t _NONE = _XPLATSTR("none"); + + std::unique_ptr c; + std::unique_ptr d; + + std::shared_ptr fcf = web::http::compression::make_compress_factory( + fake_provider::FAKE, []() -> std::unique_ptr { + return std::make_unique(); + }); + std::vector> fcv; + fcv.push_back(fcf); + std::shared_ptr fdf = + web::http::compression::make_decompress_factory( + fake_provider::FAKE, 800, []() -> std::unique_ptr { + return std::make_unique(); + }); + std::vector> fdv; + fdv.push_back(fdf); + + std::shared_ptr ncf = web::http::compression::make_compress_factory( + _NONE, []() -> std::unique_ptr { + return std::make_unique(); + }); + std::vector> ncv; + ncv.push_back(ncf); + std::shared_ptr ndf = + web::http::compression::make_decompress_factory( + _NONE, 800, []() -> std::unique_ptr { + return std::make_unique(); + }); + std::vector> ndv; + ndv.push_back(ndf); + + // Supported algorithms + VERIFY_ARE_EQUAL( + web::http::compression::builtin::supported(), + web::http::compression::builtin::algorithm::supported(web::http::compression::builtin::algorithm::GZIP)); + VERIFY_ARE_EQUAL( + web::http::compression::builtin::supported(), + web::http::compression::builtin::algorithm::supported(web::http::compression::builtin::algorithm::DEFLATE)); + if (web::http::compression::builtin::algorithm::supported(web::http::compression::builtin::algorithm::BROTLI)) + { + VERIFY_IS_TRUE(web::http::compression::builtin::supported()); + } + VERIFY_IS_FALSE(web::http::compression::builtin::algorithm::supported(_XPLATSTR(""))); + VERIFY_IS_FALSE(web::http::compression::builtin::algorithm::supported(_XPLATSTR("foo"))); + + // Strings that double as both Transfer-Encoding and TE + std::vector encodings = {_XPLATSTR("gzip"), + _XPLATSTR("gZip "), + _XPLATSTR(" GZIP"), + _XPLATSTR(" gzip "), + _XPLATSTR(" gzip , chunked "), + _XPLATSTR(" gZip , chunked "), + _XPLATSTR("GZIP,chunked")}; + + // Similar, but geared to match a non-built-in algorithm + std::vector fake = {_XPLATSTR("fake"), + _XPLATSTR("faKe "), + _XPLATSTR(" FAKE"), + _XPLATSTR(" fake "), + _XPLATSTR(" fake , chunked "), + _XPLATSTR(" faKe , chunked "), + _XPLATSTR("FAKE,chunked")}; + + std::vector invalid = {_XPLATSTR(","), + _XPLATSTR(",gzip"), + _XPLATSTR("gzip,"), + _XPLATSTR(",gzip, chunked"), + _XPLATSTR(" ,gzip, chunked"), + _XPLATSTR("gzip, chunked,"), + _XPLATSTR("gzip, chunked, "), + _XPLATSTR("gzip,, chunked"), + _XPLATSTR("gzip , , chunked"), + _XPLATSTR("foo")}; + + std::vector invalid_tes = { + _XPLATSTR("deflate;q=0.5, gzip;q=2"), + _XPLATSTR("deflate;q=1.5, gzip;q=1"), + }; + + std::vector empty = {_XPLATSTR(""), _XPLATSTR(" ")}; + + // Repeat for Transfer-Encoding (which also covers part of TE) and Content-Encoding (which also covers all of + // Accept-Encoding) + for (int transfer = 0; transfer < 2; transfer++) + { + web::http::compression::details::header_types ctype = + transfer ? web::http::compression::details::header_types::te + : web::http::compression::details::header_types::accept_encoding; + web::http::compression::details::header_types dtype = + transfer ? web::http::compression::details::header_types::transfer_encoding + : web::http::compression::details::header_types::content_encoding; + + // No compression - Transfer-Encoding + d = web::http::compression::details::get_decompressor_from_header( + _XPLATSTR(" chunked "), web::http::compression::details::header_types::transfer_encoding); + VERIFY_IS_FALSE((bool)d); + + for (auto encoding = encodings.begin(); encoding != encodings.end(); encoding++) + { + bool has_comma = false; + + has_comma = encoding->find(_XPLATSTR(",")) != utility::string_t::npos; + + // Built-in only + c = web::http::compression::details::get_compressor_from_header(*encoding, ctype); + VERIFY_ARE_EQUAL((bool)c, web::http::compression::builtin::supported()); + if (c) + { + VERIFY_ARE_EQUAL(c->algorithm(), web::http::compression::builtin::algorithm::GZIP); + } + + try + { + d = web::http::compression::details::get_decompressor_from_header(*encoding, dtype); + VERIFY_ARE_EQUAL((bool)d, web::http::compression::builtin::supported()); + if (d) + { + VERIFY_ARE_EQUAL(d->algorithm(), web::http::compression::builtin::algorithm::GZIP); + } + } + catch (http_exception) + { + VERIFY_IS_TRUE(transfer == !has_comma); + } + } + + for (auto encoding = fake.begin(); encoding != fake.end(); encoding++) + { + bool has_comma = false; + + has_comma = encoding->find(_XPLATSTR(",")) != utility::string_t::npos; + + // Supplied compressor/decompressor + c = web::http::compression::details::get_compressor_from_header(*encoding, ctype, fcv); + VERIFY_IS_TRUE((bool)c); + VERIFY_IS_TRUE(c->algorithm() == fcf->algorithm()); + + try + { + d = web::http::compression::details::get_decompressor_from_header(*encoding, dtype, fdv); + VERIFY_IS_TRUE((bool)d); + VERIFY_IS_TRUE(d->algorithm() == fdf->algorithm()); + } + catch (http_exception) + { + VERIFY_IS_TRUE(transfer == !has_comma); + } + + // No matching compressor + c = web::http::compression::details::get_compressor_from_header(*encoding, ctype, ncv); + VERIFY_IS_FALSE((bool)c); + + try + { + d = web::http::compression::details::get_decompressor_from_header(*encoding, dtype, ndv); + VERIFY_IS_FALSE(true); + } + catch (http_exception) + { + } + } + + // Negative tests - invalid headers, no matching algorithm, etc. + for (auto encoding = invalid.begin(); encoding != invalid.end(); encoding++) + { + try + { + c = web::http::compression::details::get_compressor_from_header(*encoding, ctype); + VERIFY_IS_TRUE(encoding->find(_XPLATSTR(",")) == utility::string_t::npos); + VERIFY_IS_FALSE((bool)c); + } + catch (http_exception) + { + } + + try + { + d = web::http::compression::details::get_decompressor_from_header(*encoding, dtype); + VERIFY_IS_TRUE(!web::http::compression::builtin::supported() && + encoding->find(_XPLATSTR(",")) == utility::string_t::npos); + VERIFY_IS_FALSE((bool)d); + } + catch (http_exception) + { + } + } + + // Negative tests - empty headers + for (auto encoding = empty.begin(); encoding != empty.end(); encoding++) + { + c = web::http::compression::details::get_compressor_from_header(*encoding, ctype); + VERIFY_IS_FALSE((bool)c); + + try + { + d = web::http::compression::details::get_decompressor_from_header(*encoding, dtype); + VERIFY_IS_FALSE(true); + } + catch (http_exception) + { + } + } + + // Negative tests - invalid rankings + for (auto te = invalid_tes.begin(); te != invalid_tes.end(); te++) + { + try + { + c = web::http::compression::details::get_compressor_from_header(*te, ctype); + VERIFY_IS_FALSE(true); + } + catch (http_exception) + { + } + } + + utility::string_t builtin; + std::vector> dv; + + // Builtins + builtin = web::http::compression::details::build_supported_header(ctype); + if (transfer) + { + VERIFY_ARE_EQUAL(!builtin.empty(), web::http::compression::builtin::supported()); + } + else + { + VERIFY_IS_FALSE(builtin.empty()); + } + + // Null decompressor - effectively forces no compression algorithms + dv.push_back(std::shared_ptr()); + builtin = web::http::compression::details::build_supported_header(ctype, dv); + VERIFY_ARE_EQUAL((bool)transfer, builtin.empty()); + dv.pop_back(); + + if (web::http::compression::builtin::supported()) + { + dv.push_back(web::http::compression::builtin::get_decompress_factory( + web::http::compression::builtin::algorithm::GZIP)); + builtin = web::http::compression::details::build_supported_header(ctype, dv); // --> "gzip;q=1.0" + VERIFY_IS_FALSE(builtin.empty()); + } + else + { + builtin = _XPLATSTR("gzip;q=1.0"); + } + + // TE- and/or Accept-Encoding-specific test cases, regenerated for each pass + std::vector tes = { + builtin, + _XPLATSTR(" deflate;q=0.777 ,foo;q=0,gzip;q=0.9, bar;q=1.0, xxx;q=1 "), + _XPLATSTR("gzip ; q=1, deflate;q=0.5"), + _XPLATSTR("gzip;q=1.0, deflate;q=0.5"), + _XPLATSTR("deflate;q=0.5, gzip;q=1"), + _XPLATSTR("gzip,deflate;q=0.7"), + _XPLATSTR("trailers,gzip,deflate;q=0.7")}; + + for (int fake = 0; fake < 2; fake++) + { + if (fake) + { + // Switch built-in vs. supplied results the second time around + for (int i = 0; i < tes.size(); i++) + { + tes[i].replace(tes[i].find(web::http::compression::builtin::algorithm::GZIP), + web::http::compression::builtin::algorithm::GZIP.size(), + fake_provider::FAKE); + if (tes[i].find(web::http::compression::builtin::algorithm::DEFLATE) != utility::string_t::npos) + { + tes[i].replace(tes[i].find(web::http::compression::builtin::algorithm::DEFLATE), + web::http::compression::builtin::algorithm::DEFLATE.size(), + _NONE); + } + } + } + + for (auto te = tes.begin(); te != tes.end(); te++) + { + // Built-in only + c = web::http::compression::details::get_compressor_from_header(*te, ctype); + if (c) + { + VERIFY_IS_TRUE(web::http::compression::builtin::supported()); + VERIFY_IS_FALSE((bool)fake); + VERIFY_ARE_EQUAL(c->algorithm(), web::http::compression::builtin::algorithm::GZIP); + } + else + { + VERIFY_IS_TRUE((bool)fake || !web::http::compression::builtin::supported()); + } + + // Supplied compressor - both matching and non-matching + c = web::http::compression::details::get_compressor_from_header(*te, ctype, fcv); + VERIFY_ARE_EQUAL((bool)c, (bool)fake); + if (c) + { + VERIFY_ARE_EQUAL(c->algorithm(), fake_provider::FAKE); + } + } + } + } + } + + template + class my_rawptr_buffer : public concurrency::streams::rawptr_buffer<_CharType> + { + public: + my_rawptr_buffer(const _CharType* data, size_t size) + : concurrency::streams::rawptr_buffer<_CharType>(data, size) + { + } + + // No acquire(), to force non-acquire compression client codepaths + virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count) + { + ptr; + count; + return false; + } + + virtual void release(_Out_writes_(count) _CharType* ptr, _In_ size_t count) + { + ptr; + count; + } + + static concurrency::streams::basic_istream<_CharType> open_istream(const _CharType* data, size_t size) + { + return concurrency::streams::basic_istream<_CharType>( + concurrency::streams::streambuf<_CharType>(std::make_shared>(data, size))); + } + }; + + TEST_FIXTURE(uri_address, compress_client_server) + { + bool processed; + bool skip_transfer_put = false; + int transfer; + + size_t buffer_sizes[] = {0, 1, 3, 4, 4096, 65536, 100000, 157890}; + + std::vector> dfactories; + std::vector> cfactories; + +#if defined(_WIN32) && !defined(CPPREST_FORCE_HTTP_CLIENT_ASIO) + // Run a quick test to see if we're dealing with older/broken winhttp for compressed transfer encoding + { + test_http_server* p_server = nullptr; + std::unique_ptr scoped = + std::move(std::make_unique(m_uri)); + scoped->server()->next_request().then([&skip_transfer_put](pplx::task op) { + try + { + op.get()->reply(static_cast(status_codes::OK)); + } + catch (std::runtime_error) + { + // The test server throws if it's destructed with outstanding tasks, + // which will happen if winhttp responds 501 without informing us + VERIFY_IS_TRUE(skip_transfer_put); + } + }); + + http_client client(m_uri); + http_request msg(methods::PUT); + msg.set_compressor(std::make_unique(0)); + msg.set_body(concurrency::streams::rawptr_stream::open_istream((const uint8_t*)nullptr, 0)); + http_response rsp = client.request(msg).get(); + rsp.content_ready().wait(); + if (rsp.status_code() == status_codes::NotImplemented) + { + skip_transfer_put = true; + } + else + { + VERIFY_IS_TRUE(rsp.status_code() == status_codes::OK); + } + } +#endif // _WIN32 + + // Test decompression both explicitly through the test server and implicitly through the listener; + // this is the top-level loop in order to avoid thrashing the listeners more than necessary + for (int real = 0; real < 2; real++) + { + web::http::experimental::listener::http_listener listener; + std::unique_ptr scoped; + test_http_server* p_server = nullptr; + std::vector v; + size_t buffer_size; + + // Start the listener, and configure callbacks if necessary + if (real) + { + listener = std::move(web::http::experimental::listener::http_listener(m_uri)); + listener.open().wait(); + listener.support(methods::PUT, [&v, &dfactories, &processed](http_request request) { + utility::string_t encoding; + http_response rsp; + + if (request.headers().match(web::http::header_names::transfer_encoding, encoding) || + request.headers().match(web::http::header_names::content_encoding, encoding)) + { + if (encoding.find(fake_provider::FAKE) != utility::string_t::npos) + { + // This one won't be found by the server in the default set... + rsp._get_impl()->set_decompress_factories(dfactories); + } + } + processed = true; + rsp.set_status_code(status_codes::OK); + request.reply(rsp); + }); + listener.support( + methods::GET, [&v, &buffer_size, &cfactories, &processed, &transfer](http_request request) { + utility::string_t encoding; + http_response rsp; + bool done; + + if (transfer) + { +#if defined(_WIN32) && !defined(__cplusplus_winrt) && !defined(CPPREST_FORCE_HTTP_CLIENT_ASIO) + // Compression happens in the listener itself + done = request.headers().match(web::http::header_names::te, encoding); + VERIFY_IS_TRUE(done); + if (encoding.find(fake_provider::FAKE) != utility::string_t::npos) + { + // This one won't be found in the server's default set... + rsp._get_impl()->set_compressor(std::make_unique(buffer_size)); + } +#endif // _WIN32 + rsp.set_body( + concurrency::streams::rawptr_stream::open_istream(v.data(), v.size())); + } + else + { + std::unique_ptr c; + std::vector pre; + size_t used; + + done = request.headers().match(web::http::header_names::accept_encoding, encoding); + VERIFY_IS_TRUE(done); + pre.resize(v.size() + 128); + c = web::http::compression::details::get_compressor_from_header( + encoding, web::http::compression::details::header_types::accept_encoding, cfactories); + VERIFY_IS_TRUE((bool)c); + auto got = c->compress(v.data(), + v.size(), + pre.data(), + pre.size(), + web::http::compression::operation_hint::is_last, + used, + &done); + VERIFY_IS_TRUE(used == v.size()); + VERIFY_IS_TRUE(done); + + // Add a single pre-compressed stream, since Content-Encoding requires Content-Length + pre.resize(got); + rsp.headers().add(header_names::content_encoding, c->algorithm()); + rsp.set_body( + concurrency::streams::container_stream>::open_istream(pre)); + } + processed = true; + rsp.set_status_code(status_codes::OK); + request.reply(rsp); + }); + } + else + { + scoped = std::move(std::make_unique(m_uri)); + p_server = scoped->server(); + } + + // Test various buffer sizes + for (int sz = 0; sz < sizeof(buffer_sizes) / sizeof(buffer_sizes[0]); sz++) + { + std::vector algs; + std::map> dmap; + + buffer_size = buffer_sizes[sz]; + + dfactories.clear(); + cfactories.clear(); + + // Re-build the sets of compress and decompress factories, to account for the buffer size in our "fake" + // ones + if (web::http::compression::builtin::algorithm::supported( + web::http::compression::builtin::algorithm::GZIP)) + { + algs.push_back(web::http::compression::builtin::algorithm::GZIP); + dmap[web::http::compression::builtin::algorithm::GZIP] = + web::http::compression::builtin::get_decompress_factory( + web::http::compression::builtin::algorithm::GZIP); + dfactories.push_back(dmap[web::http::compression::builtin::algorithm::GZIP]); + cfactories.push_back(web::http::compression::builtin::get_compress_factory( + web::http::compression::builtin::algorithm::GZIP)); + } + if (web::http::compression::builtin::algorithm::supported( + web::http::compression::builtin::algorithm::DEFLATE)) + { + algs.push_back(web::http::compression::builtin::algorithm::DEFLATE); + dmap[web::http::compression::builtin::algorithm::DEFLATE] = + web::http::compression::builtin::get_decompress_factory( + web::http::compression::builtin::algorithm::DEFLATE); + dfactories.push_back(dmap[web::http::compression::builtin::algorithm::DEFLATE]); + cfactories.push_back(web::http::compression::builtin::get_compress_factory( + web::http::compression::builtin::algorithm::DEFLATE)); + } + if (web::http::compression::builtin::algorithm::supported( + web::http::compression::builtin::algorithm::BROTLI)) + { + algs.push_back(web::http::compression::builtin::algorithm::BROTLI); + dmap[web::http::compression::builtin::algorithm::BROTLI] = + web::http::compression::builtin::get_decompress_factory( + web::http::compression::builtin::algorithm::BROTLI); + dfactories.push_back(dmap[web::http::compression::builtin::algorithm::BROTLI]); + cfactories.push_back(web::http::compression::builtin::get_compress_factory( + web::http::compression::builtin::algorithm::BROTLI)); + } + algs.push_back(fake_provider::FAKE); + dmap[fake_provider::FAKE] = web::http::compression::make_decompress_factory( + fake_provider::FAKE, + 1000, + [buffer_size]() -> std::unique_ptr { + return std::make_unique(buffer_size); + }); + dfactories.push_back(dmap[fake_provider::FAKE]); + cfactories.push_back(web::http::compression::make_compress_factory( + fake_provider::FAKE, [buffer_size]() -> std::unique_ptr { + return std::make_unique(buffer_size); + })); + + v.resize(buffer_size); + + // Test compressible (net shrinking) and non-compressible (net growing) buffers + for (int compressible = 0; compressible < 2; compressible++) + { + for (size_t x = 0; x < buffer_size; x++) + { + if (compressible) + { + v[x] = static_cast('a' + x % 26); + } + else + { + v[x] = static_cast(std::rand()); + } + } + + // Test both Transfer-Encoding and Content-Encoding + for (transfer = 0; transfer < 2; transfer++) + { + web::http::client::http_client_config config; + config.set_request_compressed_response(!transfer); + http_client client(m_uri, config); + + // Test supported compression algorithms + for (int alg = 0; alg < algs.size(); alg++) + { + // Test both GET and PUT + for (int put = 0; put < 2; put++) + { + if (transfer && put && skip_transfer_put) + { + continue; + } + + processed = false; + + if (put) + { + std::vector streams; + std::vector pre; + + if (transfer) + { + // Add a pair of non-compressed streams for Transfer-Encoding, one with and one + // without acquire/release support + streams.emplace_back(concurrency::streams::rawptr_stream::open_istream( + (const uint8_t*)v.data(), v.size())); + streams.emplace_back( + my_rawptr_buffer::open_istream(v.data(), v.size())); + } + else + { + bool done; + size_t used; + pre.resize(v.size() + 128); + + auto c = web::http::compression::builtin::make_compressor(algs[alg]); + if (algs[alg] == fake_provider::FAKE) + { + VERIFY_IS_FALSE((bool)c); + c = std::make_unique(buffer_size); + } + VERIFY_IS_TRUE((bool)c); + auto got = c->compress(v.data(), + v.size(), + pre.data(), + pre.size(), + web::http::compression::operation_hint::is_last, + used, + &done); + VERIFY_ARE_EQUAL(used, v.size()); + VERIFY_IS_TRUE(done); + + // Add a single pre-compressed stream, since Content-Encoding requires + // Content-Length + streams.emplace_back(concurrency::streams::rawptr_stream::open_istream( + pre.data(), got)); + } + + for (int str = 0; str < streams.size(); str++) + { + concurrency::streams::istream& stream = streams[str]; + http_request msg(methods::PUT); + + processed = false; + + msg.set_body(stream); + if (transfer) + { + bool boo = msg.set_compressor(algs[alg]); + VERIFY_ARE_EQUAL(boo, algs[alg] != fake_provider::FAKE); + if (algs[alg] == fake_provider::FAKE) + { + msg.set_compressor(std::make_unique(buffer_size)); + } + } + else + { + msg.headers().add(header_names::content_encoding, algs[alg]); + } + + if (!real) + { + // We implement the decompression path in the server, to prove that valid, + // compressed data is sent + p_server->next_request().then([&](test_request* p_request) { + std::unique_ptr d; + std::vector vv; + utility::string_t header; + size_t used; + size_t got; + bool done; + + http_asserts::assert_test_request_equals( + p_request, methods::PUT, U("/")); + + if (transfer) + { + VERIFY_IS_FALSE(p_request->match_header( + header_names::content_encoding, header)); + done = p_request->match_header(header_names::transfer_encoding, + header); + VERIFY_IS_TRUE(done); + d = web::http::compression::details::get_decompressor_from_header( + header, + web::http::compression::details::header_types:: + transfer_encoding, + dfactories); + } + else + { + done = p_request->match_header(header_names::transfer_encoding, + header); + if (done) + { + VERIFY_IS_TRUE( + utility::details::str_iequal(_XPLATSTR("chunked"), header)); + } + done = + p_request->match_header(header_names::content_encoding, header); + VERIFY_IS_TRUE(done); + d = web::http::compression::details::get_decompressor_from_header( + header, + web::http::compression::details::header_types::content_encoding, + dfactories); + } +#if defined(_WIN32) && !defined(__cplusplus_winrt) && !defined(CPPREST_FORCE_HTTP_CLIENT_ASIO) + VERIFY_IS_TRUE((bool)d); +#else // _WIN32 + VERIFY_ARE_NOT_EQUAL((bool)d, !!transfer); +#endif // _WIN32 + + vv.resize(buffer_size + 128); + if (d) + { + got = d->decompress(p_request->m_body.data(), + p_request->m_body.size(), + vv.data(), + vv.size(), + web::http::compression::operation_hint::is_last, + used, + &done); + VERIFY_ARE_EQUAL(used, p_request->m_body.size()); + VERIFY_IS_TRUE(done); + } + else + { + memcpy(vv.data(), v.data(), v.size()); + got = v.size(); + } + VERIFY_ARE_EQUAL(buffer_size, got); + vv.resize(buffer_size); + VERIFY_ARE_EQUAL(v, vv); + processed = true; + + p_request->reply(static_cast(status_codes::OK)); + }); + } + + // Send the request + http_response rsp = client.request(msg).get(); + VERIFY_ARE_EQUAL(rsp.status_code(), status_codes::OK); + rsp.content_ready().wait(); + stream.close().wait(); + VERIFY_IS_TRUE(processed); + } + } + else + { + std::vector vv; + concurrency::streams::ostream stream = + concurrency::streams::rawptr_stream::open_ostream(vv.data(), + buffer_size); + http_request msg(methods::GET); + + std::vector> df = { + dmap[algs[alg]]}; + msg.set_decompress_factories(df); + + vv.resize(buffer_size + 128); // extra to ensure no overflow + + concurrency::streams::rawptr_buffer buf( + vv.data(), vv.size(), std::ios::out); + + if (!real) + { + p_server->next_request().then([&](test_request* p_request) { + std::map headers; + std::unique_ptr c; + utility::string_t header; + std::vector cmp; + size_t used; + size_t extra = 0; + size_t skip = 0; + size_t got; + bool done; + + std::string ext = ";x=y"; + std::string trailer = "a=b\r\nx=y\r\n"; + + http_asserts::assert_test_request_equals(p_request, methods::GET, U("/")); + + if (transfer) + { + // On Windows, someone along the way adds "Accept-Encoding: peerdist", + // so we can't unconditionally assert that Accept-Encoding is not + // present + done = p_request->match_header(header_names::accept_encoding, header); + VERIFY_IS_TRUE(!done || + header.find(algs[alg]) == utility::string_t::npos); + done = p_request->match_header(header_names::te, header); + if (done) + { + c = web::http::compression::details::get_compressor_from_header( + header, + web::http::compression::details::header_types::te, + cfactories); + } + + // Account for space for the chunk header and delimiters, plus a chunk + // extension and a chunked trailer part + extra = 2 * web::http::details::chunked_encoding:: + additional_encoding_space + + ext.size() + trailer.size(); + skip = web::http::details::chunked_encoding::data_offset + ext.size(); + } + else + { + VERIFY_IS_FALSE(p_request->match_header(header_names::te, header)); + done = p_request->match_header(header_names::accept_encoding, header); + VERIFY_IS_TRUE(done); + c = web::http::compression::details::get_compressor_from_header( + header, + web::http::compression::details::header_types::accept_encoding, + cfactories); + } +#if !defined __cplusplus_winrt + VERIFY_IS_TRUE((bool)c); +#else // __cplusplus_winrt + VERIFY_ARE_NOT_EQUAL((bool)c, !!transfer); +#endif // __cplusplus_winrt + cmp.resize(extra + buffer_size + 128); + if (c) + { + got = c->compress(v.data(), + v.size(), + cmp.data() + skip, + cmp.size() - extra, + web::http::compression::operation_hint::is_last, + used, + &done); + VERIFY_ARE_EQUAL(used, v.size()); + VERIFY_IS_TRUE(done); + } + else + { + memcpy(cmp.data() + skip, v.data(), v.size()); + got = v.size(); + } + if (transfer) + { + // Add delimiters for the first (and only) data chunk, plus the final + // 0-length chunk, and hack in a dummy chunk extension and a dummy + // trailer part. Note that we put *two* "0\r\n" in here in the 0-length + // case... and none of the parsers complain. + size_t total = + got + + web::http::details::chunked_encoding::additional_encoding_space + + ext.size(); + _ASSERTE(ext.size() >= 2); + if (got > ext.size() - 1) + { + cmp[total - 2] = + cmp[got + web::http::details::chunked_encoding::data_offset]; + } + if (got > ext.size() - 2) + { + cmp[total - 1] = + cmp[got + web::http::details::chunked_encoding::data_offset + + 1]; + } + size_t offset = + web::http::details::chunked_encoding::add_chunked_delimiters( + cmp.data(), total, got); + size_t offset2 = + web::http::details::chunked_encoding::add_chunked_delimiters( + cmp.data() + total - 7, + web::http::details::chunked_encoding::additional_encoding_space, + 0); + _ASSERTE( + offset2 == 7 && + web::http::details::chunked_encoding::additional_encoding_space - + 7 == + 5); + memcpy(cmp.data() + web::http::details::chunked_encoding::data_offset - + 2, + ext.data(), + ext.size()); + cmp[web::http::details::chunked_encoding::data_offset + ext.size() - + 2] = '\r'; + cmp[web::http::details::chunked_encoding::data_offset + ext.size() - + 1] = '\n'; + if (got > ext.size() - 1) + { + cmp[got + web::http::details::chunked_encoding::data_offset] = + cmp[total - 2]; + } + if (got > ext.size() - 2) + { + cmp[got + web::http::details::chunked_encoding::data_offset + 1] = + cmp[total - 1]; + } + cmp[total - 2] = '\r'; + cmp[total - 1] = '\n'; + memcpy(cmp.data() + total + 3, trailer.data(), trailer.size()); + cmp[total + trailer.size() + 3] = '\r'; + cmp[total + trailer.size() + 4] = '\n'; + cmp.erase(cmp.begin(), cmp.begin() + offset); + cmp.resize( + ext.size() + got + trailer.size() + + web::http::details::chunked_encoding::additional_encoding_space - + offset + 5); + if (c) + { + headers[header_names::transfer_encoding] = + c->algorithm() + _XPLATSTR(", chunked"); + } + else + { + headers[header_names::transfer_encoding] = _XPLATSTR("chunked"); + } + } + else + { + cmp.resize(got); + headers[header_names::content_encoding] = c->algorithm(); + } + processed = true; + + if (cmp.size()) + { + p_request->reply(static_cast(status_codes::OK), + utility::string_t(), + headers, + cmp); + } + else + { + p_request->reply(static_cast(status_codes::OK), + utility::string_t(), + headers); + } + }); + } + + // Common send and response processing code + http_response rsp = client.request(msg).get(); + VERIFY_ARE_EQUAL(rsp.status_code(), status_codes::OK); + VERIFY_NO_THROWS(rsp.content_ready().wait()); + + if (transfer) + { + VERIFY_IS_TRUE(rsp.headers().has(header_names::transfer_encoding)); + VERIFY_IS_FALSE(rsp.headers().has(header_names::content_encoding)); + } + else + { + utility::string_t header; + + VERIFY_IS_TRUE(rsp.headers().has(header_names::content_encoding)); + bool boo = rsp.headers().match(header_names::transfer_encoding, header); + if (boo) + { + VERIFY_IS_TRUE(utility::details::str_iequal(_XPLATSTR("chunked"), header)); + } + } + + size_t offset; + VERIFY_NO_THROWS(offset = rsp.body().read_to_end(buf).get()); + VERIFY_ARE_EQUAL(offset, buffer_size); + VERIFY_ARE_EQUAL(offset, static_cast(buf.getpos(std::ios::out))); + vv.resize(buffer_size); + VERIFY_ARE_EQUAL(v, vv); + buf.close(std::ios_base::out).wait(); + stream.close().wait(); + } + VERIFY_IS_TRUE(processed); + } + } + } + } + } + if (real) + { + listener.close().wait(); + } + } + } +} // SUITE(request_helper_tests) +} +} +} +} diff --git a/Release/tests/functional/http/client/outside_tests.cpp b/Release/tests/functional/http/client/outside_tests.cpp index 7c0438d48c..bec9b0c458 100644 --- a/Release/tests/functional/http/client/outside_tests.cpp +++ b/Release/tests/functional/http/client/outside_tests.cpp @@ -58,7 +58,7 @@ TEST_FIXTURE(uri_address, outside_cnn_dot_com) TEST_FIXTURE(uri_address, outside_wikipedia_compressed_http_response) { - if (web::http::details::compression::stream_decompressor::is_supported() == false) + if (web::http::compression::builtin::supported() == false) { // On platforms which do not support compressed http, nothing to check. return; diff --git a/Release/tests/functional/http/client/request_helper_tests.cpp b/Release/tests/functional/http/client/request_helper_tests.cpp index 32a49490ef..fa3360756b 100644 --- a/Release/tests/functional/http/client/request_helper_tests.cpp +++ b/Release/tests/functional/http/client/request_helper_tests.cpp @@ -45,7 +45,7 @@ TEST_FIXTURE(uri_address, do_not_fail_on_content_encoding_when_not_requested) TEST_FIXTURE(uri_address, fail_on_content_encoding_if_unsupported) { - if (web::http::details::compression::stream_compressor::is_supported()) + if (web::http::compression::builtin::supported()) { test_http_server::scoped_server scoped(m_uri); auto& server = *scoped.server(); @@ -63,7 +63,7 @@ TEST_FIXTURE(uri_address, fail_on_content_encoding_if_unsupported) TEST_FIXTURE(uri_address, send_accept_encoding) { - if (web::http::details::compression::stream_compressor::is_supported()) + if (web::http::compression::builtin::supported()) { test_http_server::scoped_server scoped(m_uri); auto& server = *scoped.server(); @@ -93,7 +93,14 @@ TEST_FIXTURE(uri_address, do_not_send_accept_encoding) std::atomic found_accept_encoding(true); server.next_request().then([&found_accept_encoding](test_request *p_request) { - found_accept_encoding = p_request->m_headers.find(header_names::accept_encoding) != p_request->m_headers.end(); + utility::string_t header; + + found_accept_encoding = p_request->match_header(header_names::accept_encoding, header); + if (found_accept_encoding) + { + // On Windows, someone along the way (not us!) adds "Accept-Encoding: peerdist" + found_accept_encoding = header != _XPLATSTR("peerdist"); + } p_request->reply(200, U("OK")); }); @@ -102,55 +109,6 @@ TEST_FIXTURE(uri_address, do_not_send_accept_encoding) VERIFY_IS_FALSE(found_accept_encoding); } -TEST_FIXTURE(uri_address, compress_and_decompress) -{ - if (web::http::details::compression::stream_compressor::is_supported()) - { - auto compress_and_decompress = [](web::http::details::compression::compression_algorithm alg) - { - auto compressor = std::make_shared(alg); - auto decompressor = std::make_shared(alg); - - const size_t buffer_size = 100; - const size_t split_pos = buffer_size / 2; - - web::http::details::compression::data_buffer input_buffer; - input_buffer.reserve(buffer_size); - - for (size_t i = 0; i < buffer_size; ++i) - { - input_buffer.push_back(static_cast(i)); - } - - web::http::details::compression::data_buffer buffer1(input_buffer.begin(), input_buffer.begin() + split_pos); - web::http::details::compression::data_buffer buffer2(input_buffer.begin() + split_pos, input_buffer.end()); - - auto compressed_data1 = compressor->compress(buffer1, false); - VERIFY_IS_FALSE(compressed_data1.empty()); - VERIFY_IS_FALSE(compressor->has_error()); - - auto compressed_data2 = compressor->compress(buffer2, true); - VERIFY_IS_FALSE(compressed_data2.empty()); - VERIFY_IS_FALSE(compressor->has_error()); - - auto decompressed_data1 = decompressor->decompress(compressed_data1); - VERIFY_IS_FALSE(decompressed_data1.empty()); - VERIFY_IS_FALSE(decompressor->has_error()); - - auto decompressed_data2 = decompressor->decompress(compressed_data2); - VERIFY_IS_FALSE(decompressed_data2.empty()); - VERIFY_IS_FALSE(decompressor->has_error()); - - decompressed_data1.insert(decompressed_data1.end(), decompressed_data2.begin(), decompressed_data2.end()); - - VERIFY_ARE_EQUAL(input_buffer, decompressed_data1); - }; - - compress_and_decompress(web::http::details::compression::compression_algorithm::gzip); - compress_and_decompress(web::http::details::compression::compression_algorithm::deflate); - } -} - TEST_FIXTURE(uri_address, non_rvalue_bodies) { test_http_server::scoped_server scoped(m_uri); diff --git a/Release/tests/functional/http/utilities/include/test_http_server.h b/Release/tests/functional/http/utilities/include/test_http_server.h index 84eb27d4ab..4b2ededbd5 100644 --- a/Release/tests/functional/http/utilities/include/test_http_server.h +++ b/Release/tests/functional/http/utilities/include/test_http_server.h @@ -46,6 +46,15 @@ class test_request return reply_impl(status_code, reason_phrase, headers, (void *)&data[0], data.size() * sizeof(utf8char)); } + unsigned long reply( + const unsigned short status_code, + const utility::string_t &reason_phrase, + const std::map &headers, + const std::vector &data) + { + return reply_impl(status_code, reason_phrase, headers, (void *)&data[0], data.size()); + } + unsigned long reply( const unsigned short status_code, const utility::string_t &reason_phrase, @@ -60,20 +69,12 @@ class test_request bool match_header(const utility::string_t & header_name, T & header_value) { auto iter = m_headers.find(header_name); - if (iter != m_headers.end()) - { - utility::istringstream_t iss(iter->second); - iss >> header_value; - if (iss.fail() || !iss.eof()) - { - return false; - } - return true; - } - else - { - return false; - } + if (iter == m_headers.end()) + { + return false; + } + + return bind_impl(iter->second, header_value) || iter->second.empty(); } // Request data. @@ -93,6 +94,33 @@ class test_request const std::map &headers, void * data, size_t data_length); + +private: + + template + bool bind_impl(const utility::string_t &text, T &ref) const + { + utility::istringstream_t iss(text); + iss.imbue(std::locale::classic()); + iss >> ref; + if (iss.fail() || !iss.eof()) + { + return false; + } + + return true; + } + + bool bind_impl(const utility::string_t &text, utf16string &ref) const + { + ref = utility::conversions::to_utf16string(text); + return true; + } + bool bind_impl(const utility::string_t &text, std::string &ref) const + { + ref = utility::conversions::to_utf8string(text); + return true; + } }; /// diff --git a/Release/tests/functional/http/utilities/test_http_server.cpp b/Release/tests/functional/http/utilities/test_http_server.cpp index cd359b1592..c4f848c009 100644 --- a/Release/tests/functional/http/utilities/test_http_server.cpp +++ b/Release/tests/functional/http/utilities/test_http_server.cpp @@ -160,7 +160,7 @@ static utility::string_t HttpServerAPIKnownHeaders[] = U("Proxy-Authorization"), U("Referer"), U("Range"), - U("Te"), + U("TE"), U("Translate"), U("User-Agent"), U("Request-Maximum"), @@ -345,7 +345,7 @@ class _test_http_server utility::string_t transfer_encoding; const bool has_transfer_encoding = p_test_request->match_header(U("Transfer-Encoding"), transfer_encoding); - if (has_transfer_encoding && transfer_encoding == U("chunked")) + if (has_transfer_encoding && transfer_encoding.find(U("chunked")) != std::string::npos) { content_length = 0; char buf[4096]; From 645637b9847438dcdf94c152f98f6659c163f777 Mon Sep 17 00:00:00 2001 From: Rishabh Anand Date: Tue, 2 Oct 2018 03:05:47 +0530 Subject: [PATCH 254/438] Linkify Visual Studio reference in README.md (#882) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4669fd8871..d6b0934320 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ target_link_libraries(main PRIVATE cpprestsdk::cpprest) * Features - HTTP client/server, JSON, URI, asynchronous streams, WebSockets client, oAuth * PPL Tasks - A powerful model for composing asynchronous operations based on C++ 11 features * Platforms - Windows desktop, Windows Store (UWP), Linux, OS X, Unix, iOS, and Android -* Support for Visual Studio 2015 and 2017 with debugger visualizers +* Support for [Visual Studio 2015 and 2017](https://visualstudio.microsoft.com/) with debugger visualizers ## Contribute Back! From b14f9ff6c48a30da8c57d1982d2e87b3c885dc59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20St=C3=B6ggl?= Date: Tue, 2 Oct 2018 00:13:21 +0200 Subject: [PATCH 255/438] Use the same cmake_minimum_required version 3.1 (#847) as in Release/CMakeLists.txt --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c66d502345..594e6be65e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.1) project(cpprestsdk-root NONE) add_subdirectory(Release) From f897582260f2942284f9213ab9027486bde21b73 Mon Sep 17 00:00:00 2001 From: Gianfranco Costamagna Date: Tue, 2 Oct 2018 01:17:19 +0200 Subject: [PATCH 256/438] Fix install (#879) * Fix default installation path * Fixup previous commit. This makes the install location not correct for Debian and similar linux distro, but upstream don't plan to change "lib/cpprestsdk" location, so at least we can override the location with -DCPPREST_EXPORT_DIR=cmake and keep the CMAKE_INSTALL_LIBDIR multiarch location --- Release/CMakeLists.txt | 2 +- Release/src/CMakeLists.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 3b99b85309..563b13d0dc 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -18,7 +18,7 @@ enable_testing() set(WERROR ON CACHE BOOL "Treat Warnings as Errors.") set(CPPREST_EXCLUDE_WEBSOCKETS OFF CACHE BOOL "Exclude websockets functionality.") set(CPPREST_EXCLUDE_COMPRESSION OFF CACHE BOOL "Exclude compression functionality.") -set(CPPREST_EXPORT_DIR lib/cpprestsdk CACHE STRING "Directory to install CMake config files.") +set(CPPREST_EXPORT_DIR cpprestsdk CACHE STRING "Directory to install CMake config files.") set(CPPREST_INSTALL_HEADERS ON CACHE BOOL "Install header files.") set(CPPREST_INSTALL ON CACHE BOOL "Add install commands.") diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index a34605bda2..050ff71fc2 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -262,12 +262,12 @@ if(CPPREST_INSTALL) install( FILES "${CMAKE_CURRENT_BINARY_DIR}/cpprestsdk-config.cmake" - DESTINATION ${CPPREST_EXPORT_DIR} + DESTINATION ${CMAKE_INSTALL_LIBDIR}/${CPPREST_EXPORT_DIR} ) install( EXPORT cpprestsdk-targets FILE cpprestsdk-targets.cmake NAMESPACE cpprestsdk:: - DESTINATION ${CPPREST_EXPORT_DIR} + DESTINATION ${CMAKE_INSTALL_LIBDIR}/${CPPREST_EXPORT_DIR} ) endif() From 982793de5ff79fb2035172511792b61e385697b0 Mon Sep 17 00:00:00 2001 From: Ernie Pistor Date: Thu, 4 Oct 2018 02:10:52 -0400 Subject: [PATCH 257/438] address review comments --- Release/cmake/cpprest_find_brotli.cmake | 2 +- Release/cmake/cpprestsdk-config.in.cmake | 2 +- Release/include/cpprest/http_compression.h | 34 ++---- Release/include/cpprest/http_headers.h | 23 ++-- Release/include/cpprest/http_msg.h | 16 +-- Release/src/CMakeLists.txt | 3 + Release/src/http/client/http_client_asio.cpp | 17 ++- .../src/http/client/http_client_winhttp.cpp | 36 +++--- Release/src/http/common/http_compression.cpp | 105 ++++++++++-------- .../src/http/common/internal_http_helpers.h | 16 +++ .../http/client/compression_tests.cpp | 50 ++++----- .../http/client/request_helper_tests.cpp | 9 +- .../http/utilities/include/test_http_server.h | 29 +---- 13 files changed, 164 insertions(+), 178 deletions(-) diff --git a/Release/cmake/cpprest_find_brotli.cmake b/Release/cmake/cpprest_find_brotli.cmake index 7366100939..2ec59a9ad9 100644 --- a/Release/cmake/cpprest_find_brotli.cmake +++ b/Release/cmake/cpprest_find_brotli.cmake @@ -3,7 +3,7 @@ function(cpprest_find_brotli) return() endif() - find_package(UNOFFICIAL-BROTLI REQUIRED) + find_package(unofficial-brotli REQUIRED) add_library(cpprestsdk_brotli_internal INTERFACE) target_link_libraries(cpprestsdk_brotli_internal INTERFACE unofficial::brotli::brotlienc unofficial::brotli::brotlidec unofficial::brotli::brotlicommon) diff --git a/Release/cmake/cpprestsdk-config.in.cmake b/Release/cmake/cpprestsdk-config.in.cmake index a00caa2f95..8b5e8a6ff3 100644 --- a/Release/cmake/cpprestsdk-config.in.cmake +++ b/Release/cmake/cpprestsdk-config.in.cmake @@ -4,7 +4,7 @@ if(@CPPREST_USES_ZLIB@) endif() if(@CPPREST_USES_BROTLI@) - find_dependency(UNOFFICIAL-BROTLI) + find_dependency(unofficial-brotli) endif() if(@CPPREST_USES_OPENSSL@) diff --git a/Release/include/cpprest/http_compression.h b/Release/include/cpprest/http_compression.h index 87b1d5dda8..13b183af00 100644 --- a/Release/include/cpprest/http_compression.h +++ b/Release/include/cpprest/http_compression.h @@ -115,24 +115,20 @@ _ASYNCRTIMP bool supported(); /// // String constants for each built-in compression algorithm, for convenient use with the factory functions /// -class algorithm +namespace algorithm { -public: - _ASYNCRTIMP static const utility::string_t GZIP; - _ASYNCRTIMP static const utility::string_t DEFLATE; - _ASYNCRTIMP static const utility::string_t BROTLI; - - /// - /// Test whether cpprestsdk was built with built-in compression support and - /// the supplied string matches a supported built-in algorithm - /// The name of the algorithm to test for built-in support. - /// True if cpprestsdk was built with built-in compression support and - /// the supplied string matches a supported built-in algorithm, and false if not. - /// - _ASYNCRTIMP static bool supported(const utility::string_t& algorithm); +constexpr utility::char_t *GZIP = _XPLATSTR("gzip"); +constexpr utility::char_t *DEFLATE = _XPLATSTR("deflate"); +constexpr utility::char_t *BROTLI = _XPLATSTR("br"); -private: - algorithm() {} +/// +/// Test whether cpprestsdk was built with built-in compression support and +/// the supplied string matches a supported built-in algorithm +/// The name of the algorithm to test for built-in support. +/// True if cpprestsdk was built with built-in compression support and +/// the supplied string matches a supported built-in algorithm, and false if not. +/// +_ASYNCRTIMP bool supported(const utility::string_t& algorithm); }; /// @@ -255,12 +251,6 @@ _ASYNCRTIMP std::shared_ptr make_decompress_factory( namespace details { -namespace builtin -{ -// Internal-only helper function -const std::vector> get_decompress_factories(); -} // namespace builtin - /// /// Header type enum for use with compressor and decompressor header parsing and building functions /// diff --git a/Release/include/cpprest/http_headers.h b/Release/include/cpprest/http_headers.h index c2e35f6079..077266a7d5 100644 --- a/Release/include/cpprest/http_headers.h +++ b/Release/include/cpprest/http_headers.h @@ -219,7 +219,7 @@ class http_headers return false; } - return bind_impl(iter->second, value) || iter->second.empty(); + return details::bind_impl(iter->second, value) || iter->second.empty(); } /// @@ -285,9 +285,14 @@ class http_headers _ASYNCRTIMP void set_date(const utility::datetime& date); private: + // Headers are stored in a map with case insensitive key. + inner_container m_headers; +}; - template - bool bind_impl(const key_type &text, _t &ref) const +namespace details +{ + template + bool bind_impl(const key_type &text, _t &ref) { utility::istringstream_t iss(text); iss.imbue(std::locale::classic()); @@ -300,20 +305,18 @@ class http_headers return true; } - bool bind_impl(const key_type &text, utf16string &ref) const + template + bool bind_impl(const key_type &text, utf16string &ref) { ref = utility::conversions::to_utf16string(text); return true; } - bool bind_impl(const key_type &text, std::string &ref) const + template + bool bind_impl(const key_type &text, std::string &ref) { ref = utility::conversions::to_utf8string(text); return true; } - - // Headers are stored in a map with case insensitive key. - inner_container m_headers; -}; - +} }} diff --git a/Release/include/cpprest/http_msg.h b/Release/include/cpprest/http_msg.h index 85840b6836..39649ef833 100644 --- a/Release/include/cpprest/http_msg.h +++ b/Release/include/cpprest/http_msg.h @@ -383,7 +383,7 @@ class http_msg_base /// Determine the remaining input stream length /// /// - /// size_t::max if the stream's remaining length cannot be determined + /// std::numeric_limits::max() if the stream's remaining length cannot be determined /// length if the stream's remaining length (which may be 0) can be determined /// /// @@ -396,7 +396,7 @@ class http_msg_base /// Determine the content length /// /// - /// size_t::max if there is content with unknown length (transfer_encoding:chunked) + /// std::numeric_limits::max() if there is content with unknown length (transfer_encoding:chunked) /// 0 if there is no content /// length if there is content with known length /// @@ -410,7 +410,7 @@ class http_msg_base /// Determine the content length, and, if necessary, manage compression in the Transfer-Encoding header /// /// - /// size_t::max if there is content with unknown length (transfer_encoding:chunked) + /// std::numeric_limits::max() if there is content with unknown length (transfer_encoding:chunked) /// 0 if there is no content /// length if there is content with known length /// @@ -739,7 +739,7 @@ class http_response /// A readable, open asynchronous stream. /// A string holding the MIME type of the message body. /// - /// This cannot be used in conjunction with any other means of setting the body of the request. + /// This cannot be used in conjunction with any external means of setting the body of the request. /// The stream will not be read until the message is sent. /// void set_body(const concurrency::streams::istream &stream, const utility::string_t &content_type = _XPLATSTR("application/octet-stream")) @@ -755,7 +755,7 @@ class http_response /// The size of the data to be sent in the body. /// A string holding the MIME type of the message body. /// - /// This cannot be used in conjunction with any other means of setting the body of the request. + /// This cannot be used in conjunction with any external means of setting the body of the request. /// The stream will not be read until the message is sent. /// void set_body(const concurrency::streams::istream &stream, utility::size64_t content_length, const utility::string_t &content_type = _XPLATSTR("application/octet-stream")) @@ -1222,7 +1222,7 @@ class http_request /// /// A pointer to an instantiated compressor of the desired type. /// - /// This cannot be used in conjunction with any other means of compression. The Transfer-Encoding + /// This cannot be used in conjunction with any external means of compression. The Transfer-Encoding /// header will be managed internally, and must not be set by the client. /// void set_compressor(std::unique_ptr compressor) @@ -1238,7 +1238,7 @@ class http_request /// True if a built-in compressor was instantiated, otherwise false. /// /// - /// This cannot be used in conjunction with any other means of compression. The Transfer-Encoding + /// This cannot be used in conjunction with any external means of compression. The Transfer-Encoding /// header will be managed internally, and must not be set by the client. /// bool set_compressor(utility::string_t algorithm) @@ -1297,7 +1297,7 @@ class http_request /// The collection of factory classes itself. /// /// - /// This cannot be used in conjunction with any other means of decompression. The TE + /// This cannot be used in conjunction with any external means of decompression. The TE /// header must not be set by the client, as it will be managed internally. /// const std::vector> &decompress_factories() const diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index a748698a45..ff0ebfc451 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -72,6 +72,9 @@ endif() # Compression component if(CPPREST_EXCLUDE_COMPRESSION) + if(NOT CPPREST_EXCLUDE_BROTLI) + message(FATAL_ERROR "Use of Brotli requires compression to be enabled") + endif() target_compile_definitions(cpprest PRIVATE -DCPPREST_EXCLUDE_COMPRESSION=1) else() cpprest_find_zlib() diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 893d36d74d..7590497420 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -1520,21 +1520,18 @@ class asio_context final : public request_context, public std::enable_shared_fro bool decompress(const uint8_t* input, size_t input_size, std::vector& output) { - size_t processed; - size_t got; - size_t inbytes; - size_t outbytes; - bool done; - // Need to guard against attempting to decompress when we're already finished or encountered an error! if (input == nullptr || input_size == 0) { return false; } - inbytes = 0; - outbytes = 0; - done = false; + size_t processed; + size_t got; + size_t inbytes = 0; + size_t outbytes = 0; + bool done = false; + try { output.resize(input_size * 3); @@ -1542,7 +1539,7 @@ class asio_context final : public request_context, public std::enable_shared_fro { if (inbytes) { - output.resize(output.size() + (input_size > 1024 ? input_size : 1024)); + output.resize(output.size() + std::max(input_size, static_cast(1024))); } got = m_decompressor->decompress(input + inbytes, input_size - inbytes, diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index d60f7ef1f5..0a135d039e 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -182,10 +182,10 @@ class memory_holder { uint8_t* m_externalData; std::vector m_internalData; - size_t m_length; + size_t m_size; public: - memory_holder() : m_externalData(nullptr), m_length(0) + memory_holder() : m_externalData(nullptr), m_size(0) { } @@ -202,7 +202,7 @@ class memory_holder { assert(block != nullptr); m_externalData = block; - m_length = length; + m_size = length; } inline bool is_internally_allocated() const @@ -215,9 +215,9 @@ class memory_holder return is_internally_allocated() ? &m_internalData[0] : m_externalData ; } - inline size_t length() const + inline size_t size() const { - return is_internally_allocated() ? m_internalData.size() : m_length; + return is_internally_allocated() ? m_internalData.size() : m_size; } }; @@ -1311,13 +1311,7 @@ class winhttp_client final : public _http_client_communicator { uint8_t *buffer; - if (!decompressor) - { - auto writebuf = pContext->_get_writebuffer(); - pContext->allocate_reply_space(writebuf.alloc(chunkSize), chunkSize); - buffer = pContext->m_body_data.get(); - } - else + if (decompressor) { // m_buffer holds the compressed data; we'll decompress into the caller's buffer later if (pContext->m_compression_state.m_buffer.capacity() < chunkSize) @@ -1326,6 +1320,12 @@ class winhttp_client final : public _http_client_communicator } buffer = pContext->m_compression_state.m_buffer.data(); } + else + { + auto writebuf = pContext->_get_writebuffer(); + pContext->allocate_reply_space(writebuf.alloc(chunkSize), chunkSize); + buffer = pContext->m_body_data.get(); + } if (!WinHttpReadData( pContext->m_request_handle, @@ -1350,15 +1350,15 @@ class winhttp_client final : public _http_client_communicator { // We could allocate less than a chunk for the compressed data here, though that // would result in more trips through this path for not-so-compressible data... - if (p_request_context->m_body_data.length() > http::details::chunked_encoding::additional_encoding_space) + if (p_request_context->m_body_data.size() > http::details::chunked_encoding::additional_encoding_space) { // If we've previously allocated space for the compressed data, don't reduce it - chunk_size = p_request_context->m_body_data.length() - http::details::chunked_encoding::additional_encoding_space; + chunk_size = p_request_context->m_body_data.size() - http::details::chunked_encoding::additional_encoding_space; } else if (p_request_context->m_remaining_to_write != std::numeric_limits::max()) { // Choose a semi-intelligent size based on how much total data is left to compress - chunk_size = std::min((size_t)p_request_context->m_remaining_to_write+128, p_request_context->m_http_client->client_config().chunksize()); + chunk_size = std::min(static_cast(p_request_context->m_remaining_to_write)+128, p_request_context->m_http_client->client_config().chunksize()); } else { @@ -1369,7 +1369,7 @@ class winhttp_client final : public _http_client_communicator else { // We're not compressing; use the smaller of the remaining data (if known) and the configured (or default) chunk size - chunk_size = std::min((size_t)p_request_context->m_remaining_to_write, p_request_context->m_http_client->client_config().chunksize()); + chunk_size = std::min(static_cast(p_request_context->m_remaining_to_write), p_request_context->m_http_client->client_config().chunksize()); } p_request_context->allocate_request_space(nullptr, chunk_size + http::details::chunked_encoding::additional_encoding_space); @@ -1590,7 +1590,7 @@ class winhttp_client final : public _http_client_communicator } else { - length = std::min((size_t)p_request_context->m_remaining_to_write, p_request_context->m_http_client->client_config().chunksize()); + length = std::min(static_cast(p_request_context->m_remaining_to_write), p_request_context->m_http_client->client_config().chunksize()); if (p_request_context->m_compression_state.m_buffer.capacity() < length) { p_request_context->m_compression_state.m_buffer.reserve(length); @@ -2182,7 +2182,7 @@ class winhttp_client final : public _http_client_communicator if (p_request_context->m_decompressor) { - size_t chunk_size = std::max((size_t)bytesRead, p_request_context->m_http_client->client_config().chunksize()); + size_t chunk_size = std::max(static_cast(bytesRead), p_request_context->m_http_client->client_config().chunksize()); p_request_context->m_compression_state.m_bytes_read = static_cast(bytesRead); p_request_context->m_compression_state.m_chunk_bytes = 0; diff --git a/Release/src/http/common/http_compression.cpp b/Release/src/http/common/http_compression.cpp index 89840b8867..e7e7f9a927 100644 --- a/Release/src/http/common/http_compression.cpp +++ b/Release/src/http/common/http_compression.cpp @@ -54,12 +54,15 @@ namespace builtin class zlib_compressor_base : public compress_provider { public: + static const utility::string_t GZIP; + static const utility::string_t DEFLATE; + zlib_compressor_base(int windowBits, int compressionLevel = Z_DEFAULT_COMPRESSION, int method = Z_DEFLATED, int strategy = Z_DEFAULT_STRATEGY, int memLevel = MAX_MEM_LEVEL) - : m_algorithm(windowBits >= 16 ? algorithm::GZIP : algorithm::DEFLATE) + : m_algorithm(windowBits >= 16 ? GZIP : DEFLATE) { m_state = deflateInit2(&m_stream, compressionLevel, method, windowBits, memLevel, strategy); } @@ -91,6 +94,11 @@ class zlib_compressor_base : public compress_provider throw std::runtime_error(std::move(ss.str())); } + if (input_size > std::numeric_limits::max() || output_size > std::numeric_limits::max()) + { + throw std::runtime_error("Compression input or output size out of range"); + } + m_stream.next_in = const_cast(input); m_stream.avail_in = static_cast(input_size); m_stream.next_out = const_cast(output); @@ -152,11 +160,15 @@ class zlib_compressor_base : public compress_provider const utility::string_t& m_algorithm; }; +const utility::string_t zlib_compressor_base::GZIP(algorithm::GZIP); +const utility::string_t zlib_compressor_base::DEFLATE(algorithm::DEFLATE); + // A shared base class for the gzip and deflate decompressors class zlib_decompressor_base : public decompress_provider { public: - zlib_decompressor_base(int windowBits) : m_algorithm(windowBits >= 16 ? algorithm::GZIP : algorithm::DEFLATE) + zlib_decompressor_base(int windowBits) + : m_algorithm(windowBits >= 16 ? zlib_compressor_base::GZIP : zlib_compressor_base::DEFLATE) { m_state = inflateInit2(&m_stream, windowBits); } @@ -188,6 +200,11 @@ class zlib_decompressor_base : public decompress_provider throw std::runtime_error(std::move(ss.str())); } + if (input_size > std::numeric_limits::max() || output_size > std::numeric_limits::max()) + { + throw std::runtime_error("Compression input or output size out of range"); + } + m_stream.next_in = const_cast(input); m_stream.avail_in = static_cast(input_size); m_stream.next_out = const_cast(output); @@ -296,15 +313,17 @@ class deflate_decompressor : public zlib_decompressor_base class brotli_compressor : public compress_provider { public: + static const utility::string_t BROTLI; + brotli_compressor(uint32_t window = BROTLI_DEFAULT_WINDOW, uint32_t quality = BROTLI_DEFAULT_QUALITY, uint32_t mode = BROTLI_DEFAULT_MODE) - : m_window(window), m_quality(quality), m_mode(mode) + : m_algorithm(BROTLI), m_window(window), m_quality(quality), m_mode(mode) { (void)reset(); } - const utility::string_t& algorithm() const { return algorithm::BROTLI; } + const utility::string_t& algorithm() const { return m_algorithm; } size_t compress(const uint8_t* input, size_t input_size, @@ -449,12 +468,15 @@ class brotli_compressor : public compress_provider uint32_t m_window; uint32_t m_quality; uint32_t m_mode; + const utility::string_t& m_algorithm; }; +const utility::string_t brotli_compressor::BROTLI(algorithm::BROTLI); + class brotli_decompressor : public decompress_provider { public: - brotli_decompressor() + brotli_decompressor() : m_algorithm(brotli_compressor::BROTLI) { try { @@ -465,7 +487,7 @@ class brotli_decompressor : public decompress_provider } } - const utility::string_t& algorithm() const { return algorithm::BROTLI; } + const utility::string_t& algorithm() const { return m_algorithm; } size_t decompress(const uint8_t* input, size_t input_size, @@ -561,30 +583,27 @@ class brotli_decompressor : public decompress_provider private: BrotliDecoderResult m_state{BROTLI_DECODER_RESULT_ERROR}; BrotliDecoderState* m_stream{nullptr}; + const utility::string_t& m_algorithm; }; #endif // CPPREST_BROTLI_COMPRESSION #endif // CPPREST_HTTP_COMPRESSION -const utility::string_t algorithm::GZIP = _XPLATSTR("gzip"); -const utility::string_t algorithm::DEFLATE = _XPLATSTR("deflate"); -const utility::string_t algorithm::BROTLI = _XPLATSTR("br"); - // Generic internal implementation of the compress_factory API class generic_compress_factory : public compress_factory { public: generic_compress_factory(const utility::string_t& algorithm, std::function()> make_compressor) - : _algorithm(algorithm), _make_compressor(make_compressor) + : m_algorithm(algorithm), _make_compressor(make_compressor) { } - const utility::string_t& algorithm() const { return _algorithm; } + const utility::string_t& algorithm() const { return m_algorithm; } std::unique_ptr make_compressor() const { return _make_compressor(); } private: - const utility::string_t _algorithm; + const utility::string_t m_algorithm; std::function()> _make_compressor; }; @@ -595,19 +614,19 @@ class generic_decompress_factory : public decompress_factory generic_decompress_factory(const utility::string_t& algorithm, uint16_t weight, std::function()> make_decompressor) - : _algorithm(algorithm), _weight(weight), _make_decompressor(make_decompressor) + : m_algorithm(algorithm), m_weight(weight), _make_decompressor(make_decompressor) { } - const utility::string_t& algorithm() const { return _algorithm; } + const utility::string_t& algorithm() const { return m_algorithm; } - const uint16_t weight() const { return _weight; } + const uint16_t weight() const { return m_weight; } std::unique_ptr make_decompressor() const { return _make_decompressor(); } private: - const utility::string_t _algorithm; - uint16_t _weight; + const utility::string_t m_algorithm; + uint16_t m_weight; std::function()> _make_decompressor; }; @@ -654,11 +673,9 @@ bool supported() { return !g_compress_factories.empty(); } bool algorithm::supported(const utility::string_t& algorithm) { - auto size = g_compress_factories.size(); - - for (int i = 0; i < size; i++) + for (auto& factory : g_compress_factories) { - if (utility::details::str_iequal(algorithm, g_compress_factories[i]->algorithm())) + if (utility::details::str_iequal(algorithm, factory->algorithm())) { return true; } @@ -670,11 +687,8 @@ bool algorithm::supported(const utility::string_t& algorithm) static std::unique_ptr _make_compressor( const std::vector>& factories, const utility::string_t& algorithm) { - auto size = factories.size(); - - for (int i = 0; i < size; i++) + for (auto& factory : factories) { - auto factory = factories[i].get(); if (factory && utility::details::str_iequal(algorithm, factory->algorithm())) { return factory->make_compressor(); @@ -692,11 +706,8 @@ std::unique_ptr make_compressor(const utility::string_t& algo static std::unique_ptr _make_decompressor( const std::vector>& factories, const utility::string_t& algorithm) { - auto size = factories.size(); - - for (int i = 0; i < size; i++) + for (auto& factory : factories) { - auto factory = factories[i].get(); if (factory && utility::details::str_iequal(algorithm, factory->algorithm())) { return factory->make_decompressor(); @@ -713,13 +724,11 @@ std::unique_ptr make_decompressor(const utility::string_t& std::shared_ptr get_compress_factory(const utility::string_t& algorithm) { - auto size = g_compress_factories.size(); - - for (int i = 0; i < size; i++) + for (auto& factory : g_compress_factories) { - if (utility::details::str_iequal(algorithm, g_compress_factories[i]->algorithm())) + if (utility::details::str_iequal(algorithm, factory->algorithm())) { - return g_compress_factories[i]; + return factory; } } @@ -728,13 +737,11 @@ std::shared_ptr get_compress_factory(const utility::string_t& std::shared_ptr get_decompress_factory(const utility::string_t& algorithm) { - auto size = g_decompress_factories.size(); - - for (int i = 0; i < size; i++) + for (auto& factory : g_decompress_factories) { - if (utility::details::str_iequal(algorithm, g_decompress_factories[i]->algorithm())) + if (utility::details::str_iequal(algorithm, factory->algorithm())) { - return g_decompress_factories[i]; + return factory; } } @@ -793,7 +800,7 @@ const std::vector> get_decompress_factories( } } // namespace builtin -static bool is_http_whitespace(utility::char_t ch) { return ch == _XPLATSTR(" ")[0] || ch == _XPLATSTR("\t")[0]; } +static bool is_http_whitespace(utility::char_t ch) { return ch == _XPLATSTR(' ') || ch == _XPLATSTR('\t'); } static void remove_surrounding_http_whitespace(const utility::string_t& encoding, size_t& start, size_t& length) { @@ -840,7 +847,7 @@ std::unique_ptr get_compressor_from_header( while (n != utility::string_t::npos) { // Tokenize by commas first - mark = encoding.find(_XPLATSTR(","), n); + mark = encoding.find(_XPLATSTR(','), n); t.start = n; t.rank = static_cast(-1); if (mark == utility::string_t::npos) @@ -858,7 +865,7 @@ std::unique_ptr get_compressor_from_header( remove_surrounding_http_whitespace(encoding, t.start, t.length); // Next split at the semicolon, if any, and deal with rank and additional whitespace - mark = encoding.find(_XPLATSTR(";")[0], t.start); + mark = encoding.find(_XPLATSTR(';'), t.start); if (mark < t.start + t.length) { end = t.start + t.length - 1; @@ -877,15 +884,15 @@ std::unique_ptr get_compressor_from_header( // Determine ranking; leading whitespace has been implicitly skipped by find(). // The ranking always starts with '1' or '0' per standard, and has at most 3 decimal places mark += 1; - t.rank = 1000 * (encoding.at(mark + 1) - _XPLATSTR("0")[0]); - if (mark + 2 < end && encoding.at(mark + 2) == _XPLATSTR(".")[0]) + t.rank = 1000 * (encoding.at(mark + 1) - _XPLATSTR('0')); + if (mark + 2 < end && encoding.at(mark + 2) == _XPLATSTR('.')) { // This is a real number rank; convert decimal part to hundreds and apply it size_t factor = 100; mark += 2; for (size_t i = mark + 1; i <= end; i++) { - t.rank += (encoding.at(i) - _XPLATSTR("0")[0]) * factor; + t.rank += (encoding.at(i) - _XPLATSTR('0')) * factor; factor /= 10; } } @@ -990,7 +997,7 @@ std::unique_ptr get_decompressor_from_header( while (n != utility::string_t::npos) { // Tokenize by commas first - comma = encoding.find(_XPLATSTR(","), n); + comma = encoding.find(_XPLATSTR(','), n); start = n; if (comma == utility::string_t::npos) { @@ -1076,9 +1083,9 @@ utility::string_t build_supported_header(header_types type, // Add all specified algorithms and their weights to the header start = true; - for (int i = 0; i < f.size(); i++) + os.imbue(std::locale::classic()); + for each (auto& factory in f) { - auto factory = f[i].get(); if (factory) { auto weight = factory->weight(); diff --git a/Release/src/http/common/internal_http_helpers.h b/Release/src/http/common/internal_http_helpers.h index 024ac84ac4..ef19612270 100644 --- a/Release/src/http/common/internal_http_helpers.h +++ b/Release/src/http/common/internal_http_helpers.h @@ -31,3 +31,19 @@ void trim_whitespace(std::basic_string &str) bool validate_method(const utility::string_t& method); }}} + +namespace web { namespace http { namespace compression { + +class compression::decompress_factory; + +namespace details { namespace builtin { + +/// +/// Helper function to get the set of built-in decompress factories +/// + +const std::vector> get_decompress_factories(); + +}} + +}}} diff --git a/Release/tests/functional/http/client/compression_tests.cpp b/Release/tests/functional/http/client/compression_tests.cpp index 2a49f2263f..e9cc9ef661 100644 --- a/Release/tests/functional/http/client/compression_tests.cpp +++ b/Release/tests/functional/http/client/compression_tests.cpp @@ -540,6 +540,7 @@ SUITE(compression_tests) _XPLATSTR(" chunked "), web::http::compression::details::header_types::transfer_encoding); VERIFY_IS_FALSE((bool)d); + utility::string_t gzip(web::http::compression::builtin::algorithm::GZIP); for (auto encoding = encodings.begin(); encoding != encodings.end(); encoding++) { bool has_comma = false; @@ -551,7 +552,7 @@ SUITE(compression_tests) VERIFY_ARE_EQUAL((bool)c, web::http::compression::builtin::supported()); if (c) { - VERIFY_ARE_EQUAL(c->algorithm(), web::http::compression::builtin::algorithm::GZIP); + VERIFY_ARE_EQUAL(c->algorithm(), gzip); } try @@ -560,7 +561,7 @@ SUITE(compression_tests) VERIFY_ARE_EQUAL((bool)d, web::http::compression::builtin::supported()); if (d) { - VERIFY_ARE_EQUAL(d->algorithm(), web::http::compression::builtin::algorithm::GZIP); + VERIFY_ARE_EQUAL(d->algorithm(), gzip); } } catch (http_exception) @@ -706,15 +707,15 @@ SUITE(compression_tests) if (fake) { // Switch built-in vs. supplied results the second time around - for (int i = 0; i < tes.size(); i++) + for (auto &te : tes) { - tes[i].replace(tes[i].find(web::http::compression::builtin::algorithm::GZIP), - web::http::compression::builtin::algorithm::GZIP.size(), + te.replace(te.find(web::http::compression::builtin::algorithm::GZIP), + gzip.size(), fake_provider::FAKE); - if (tes[i].find(web::http::compression::builtin::algorithm::DEFLATE) != utility::string_t::npos) + if (te.find(web::http::compression::builtin::algorithm::DEFLATE) != utility::string_t::npos) { - tes[i].replace(tes[i].find(web::http::compression::builtin::algorithm::DEFLATE), - web::http::compression::builtin::algorithm::DEFLATE.size(), + te.replace(te.find(web::http::compression::builtin::algorithm::DEFLATE), + utility::string_t(web::http::compression::builtin::algorithm::DEFLATE).size(), _NONE); } } @@ -728,7 +729,7 @@ SUITE(compression_tests) { VERIFY_IS_TRUE(web::http::compression::builtin::supported()); VERIFY_IS_FALSE((bool)fake); - VERIFY_ARE_EQUAL(c->algorithm(), web::http::compression::builtin::algorithm::GZIP); + VERIFY_ARE_EQUAL(c->algorithm(), gzip); } else { @@ -919,7 +920,7 @@ SUITE(compression_tests) // Test various buffer sizes for (int sz = 0; sz < sizeof(buffer_sizes) / sizeof(buffer_sizes[0]); sz++) { - std::vector algs; + std::vector algorithms; std::map> dmap; buffer_size = buffer_sizes[sz]; @@ -932,7 +933,7 @@ SUITE(compression_tests) if (web::http::compression::builtin::algorithm::supported( web::http::compression::builtin::algorithm::GZIP)) { - algs.push_back(web::http::compression::builtin::algorithm::GZIP); + algorithms.push_back(web::http::compression::builtin::algorithm::GZIP); dmap[web::http::compression::builtin::algorithm::GZIP] = web::http::compression::builtin::get_decompress_factory( web::http::compression::builtin::algorithm::GZIP); @@ -943,7 +944,7 @@ SUITE(compression_tests) if (web::http::compression::builtin::algorithm::supported( web::http::compression::builtin::algorithm::DEFLATE)) { - algs.push_back(web::http::compression::builtin::algorithm::DEFLATE); + algorithms.push_back(web::http::compression::builtin::algorithm::DEFLATE); dmap[web::http::compression::builtin::algorithm::DEFLATE] = web::http::compression::builtin::get_decompress_factory( web::http::compression::builtin::algorithm::DEFLATE); @@ -954,7 +955,7 @@ SUITE(compression_tests) if (web::http::compression::builtin::algorithm::supported( web::http::compression::builtin::algorithm::BROTLI)) { - algs.push_back(web::http::compression::builtin::algorithm::BROTLI); + algorithms.push_back(web::http::compression::builtin::algorithm::BROTLI); dmap[web::http::compression::builtin::algorithm::BROTLI] = web::http::compression::builtin::get_decompress_factory( web::http::compression::builtin::algorithm::BROTLI); @@ -962,7 +963,7 @@ SUITE(compression_tests) cfactories.push_back(web::http::compression::builtin::get_compress_factory( web::http::compression::builtin::algorithm::BROTLI)); } - algs.push_back(fake_provider::FAKE); + algorithms.push_back(fake_provider::FAKE); dmap[fake_provider::FAKE] = web::http::compression::make_decompress_factory( fake_provider::FAKE, 1000, @@ -1000,7 +1001,7 @@ SUITE(compression_tests) http_client client(m_uri, config); // Test supported compression algorithms - for (int alg = 0; alg < algs.size(); alg++) + for (auto& algorithm : algorithms) { // Test both GET and PUT for (int put = 0; put < 2; put++) @@ -1032,8 +1033,8 @@ SUITE(compression_tests) size_t used; pre.resize(v.size() + 128); - auto c = web::http::compression::builtin::make_compressor(algs[alg]); - if (algs[alg] == fake_provider::FAKE) + auto c = web::http::compression::builtin::make_compressor(algorithm); + if (algorithm == fake_provider::FAKE) { VERIFY_IS_FALSE((bool)c); c = std::make_unique(buffer_size); @@ -1055,9 +1056,8 @@ SUITE(compression_tests) pre.data(), got)); } - for (int str = 0; str < streams.size(); str++) + for (auto &stream : streams) { - concurrency::streams::istream& stream = streams[str]; http_request msg(methods::PUT); processed = false; @@ -1065,16 +1065,16 @@ SUITE(compression_tests) msg.set_body(stream); if (transfer) { - bool boo = msg.set_compressor(algs[alg]); - VERIFY_ARE_EQUAL(boo, algs[alg] != fake_provider::FAKE); - if (algs[alg] == fake_provider::FAKE) + bool boo = msg.set_compressor(algorithm); + VERIFY_ARE_EQUAL(boo, algorithm != fake_provider::FAKE); + if (algorithm == fake_provider::FAKE) { msg.set_compressor(std::make_unique(buffer_size)); } } else { - msg.headers().add(header_names::content_encoding, algs[alg]); + msg.headers().add(header_names::content_encoding, algorithm); } if (!real) @@ -1172,7 +1172,7 @@ SUITE(compression_tests) http_request msg(methods::GET); std::vector> df = { - dmap[algs[alg]]}; + dmap[algorithm]}; msg.set_decompress_factories(df); vv.resize(buffer_size + 128); // extra to ensure no overflow @@ -1205,7 +1205,7 @@ SUITE(compression_tests) // present done = p_request->match_header(header_names::accept_encoding, header); VERIFY_IS_TRUE(!done || - header.find(algs[alg]) == utility::string_t::npos); + header.find(algorithm) == utility::string_t::npos); done = p_request->match_header(header_names::te, header); if (done) { diff --git a/Release/tests/functional/http/client/request_helper_tests.cpp b/Release/tests/functional/http/client/request_helper_tests.cpp index fa3360756b..ee4ff762b6 100644 --- a/Release/tests/functional/http/client/request_helper_tests.cpp +++ b/Release/tests/functional/http/client/request_helper_tests.cpp @@ -95,12 +95,9 @@ TEST_FIXTURE(uri_address, do_not_send_accept_encoding) server.next_request().then([&found_accept_encoding](test_request *p_request) { utility::string_t header; - found_accept_encoding = p_request->match_header(header_names::accept_encoding, header); - if (found_accept_encoding) - { - // On Windows, someone along the way (not us!) adds "Accept-Encoding: peerdist" - found_accept_encoding = header != _XPLATSTR("peerdist"); - } + // On Windows, someone along the way (not us!) adds "Accept-Encoding: peerdist" + found_accept_encoding = + p_request->match_header(header_names::accept_encoding, header) && header != _XPLATSTR("peerdist"); p_request->reply(200, U("OK")); }); diff --git a/Release/tests/functional/http/utilities/include/test_http_server.h b/Release/tests/functional/http/utilities/include/test_http_server.h index 4b2ededbd5..8220f0b331 100644 --- a/Release/tests/functional/http/utilities/include/test_http_server.h +++ b/Release/tests/functional/http/utilities/include/test_http_server.h @@ -74,7 +74,7 @@ class test_request return false; } - return bind_impl(iter->second, header_value) || iter->second.empty(); + return web::http::details::bind_impl(iter->second, header_value) || iter->second.empty(); } // Request data. @@ -94,33 +94,6 @@ class test_request const std::map &headers, void * data, size_t data_length); - -private: - - template - bool bind_impl(const utility::string_t &text, T &ref) const - { - utility::istringstream_t iss(text); - iss.imbue(std::locale::classic()); - iss >> ref; - if (iss.fail() || !iss.eof()) - { - return false; - } - - return true; - } - - bool bind_impl(const utility::string_t &text, utf16string &ref) const - { - ref = utility::conversions::to_utf16string(text); - return true; - } - bool bind_impl(const utility::string_t &text, std::string &ref) const - { - ref = utility::conversions::to_utf8string(text); - return true; - } }; /// From ed94a6cddb46f2e216997b85bc6c1f04ffb510c6 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Mon, 8 Oct 2018 19:25:17 -0700 Subject: [PATCH 258/438] Fix build breaks on GCC 5.4, iOS, and OSX (#894) * Move up bind_impl so that it can be found by non-MSVC. * Avoid useless qualification making GCC unhappy. * Make GZIP/DEFLATE/BROTLI constant chars. * Remove unneeded ; * Remove broken qualification attempting to forward declare web::http::compression::decompress_factory. * Don't use nonstandard for each. * Remove another unnecessary const. * Mark unused parameters with (void). * Guard -Wno-format-truncation from GCC 5.4. * Fix bogus writtenSize warning from GCC 5.4. * Attempt to avoid std::make_unique in compression tests. * Avoid Concurrency::task_group_status because gcc 5.4 hates it for some reason. --- Release/CMakeLists.txt | 6 +- Release/include/cpprest/http_compression.h | 10 +-- Release/include/cpprest/http_headers.h | 62 +++++++++---------- Release/src/http/client/http_client_asio.cpp | 1 + Release/src/http/common/http_compression.cpp | 17 ++++- .../src/http/common/internal_http_helpers.h | 2 +- .../http/client/compression_tests.cpp | 45 +++++++------- 7 files changed, 80 insertions(+), 63 deletions(-) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 4a5bdef421..00fa7a7d11 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -187,7 +187,11 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR IOS) elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") message("-- Setting gcc options") - set(WARNINGS -Wall -Wextra -Wunused-parameter -Wcast-align -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls -Wunreachable-code -Wno-format-truncation) + set(WARNINGS -Wall -Wextra -Wunused-parameter -Wcast-align -Wcast-qual -Wconversion -Wformat=2 -Winit-self -Winvalid-pch -Wmissing-format-attribute -Wmissing-include-dirs -Wpacked -Wredundant-decls -Wunreachable-code) + if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6.0") + set(WARNINGS ${WARNINGS} -Wno-format-truncation) + endif() + set(LD_FLAGS "${LD_FLAGS} -Wl,-z,defs") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-strict-aliasing") diff --git a/Release/include/cpprest/http_compression.h b/Release/include/cpprest/http_compression.h index 13b183af00..1993e6244c 100644 --- a/Release/include/cpprest/http_compression.h +++ b/Release/include/cpprest/http_compression.h @@ -96,7 +96,7 @@ class decompress_factory { public: virtual const utility::string_t& algorithm() const = 0; - virtual const uint16_t weight() const = 0; + virtual uint16_t weight() const = 0; virtual std::unique_ptr make_decompressor() const = 0; virtual ~decompress_factory() = default; }; @@ -117,9 +117,9 @@ _ASYNCRTIMP bool supported(); /// namespace algorithm { -constexpr utility::char_t *GZIP = _XPLATSTR("gzip"); -constexpr utility::char_t *DEFLATE = _XPLATSTR("deflate"); -constexpr utility::char_t *BROTLI = _XPLATSTR("br"); +constexpr const utility::char_t *GZIP = _XPLATSTR("gzip"); +constexpr const utility::char_t *DEFLATE = _XPLATSTR("deflate"); +constexpr const utility::char_t *BROTLI = _XPLATSTR("br"); /// /// Test whether cpprestsdk was built with built-in compression support and @@ -129,7 +129,7 @@ constexpr utility::char_t *BROTLI = _XPLATSTR("br"); /// the supplied string matches a supported built-in algorithm, and false if not. /// _ASYNCRTIMP bool supported(const utility::string_t& algorithm); -}; +} /// /// Factory function to instantiate a built-in compression provider with default parameters by compression algorithm diff --git a/Release/include/cpprest/http_headers.h b/Release/include/cpprest/http_headers.h index 077266a7d5..3761940c8b 100644 --- a/Release/include/cpprest/http_headers.h +++ b/Release/include/cpprest/http_headers.h @@ -57,6 +57,37 @@ bool bind(const key_type &text, utility::string_t &ref) //const return true; } +namespace details +{ + template + bool bind_impl(const key_type &text, _t &ref) + { + utility::istringstream_t iss(text); + iss.imbue(std::locale::classic()); + iss >> ref; + if (iss.fail() || !iss.eof()) + { + return false; + } + + return true; + } + + template + bool bind_impl(const key_type &text, utf16string &ref) + { + ref = utility::conversions::to_utf16string(text); + return true; + } + + template + bool bind_impl(const key_type &text, std::string &ref) + { + ref = utility::conversions::to_utf8string(text); + return true; + } +} + /// /// Represents HTTP headers, acts like a map. /// @@ -288,35 +319,4 @@ class http_headers // Headers are stored in a map with case insensitive key. inner_container m_headers; }; - -namespace details -{ - template - bool bind_impl(const key_type &text, _t &ref) - { - utility::istringstream_t iss(text); - iss.imbue(std::locale::classic()); - iss >> ref; - if (iss.fail() || !iss.eof()) - { - return false; - } - - return true; - } - - template - bool bind_impl(const key_type &text, utf16string &ref) - { - ref = utility::conversions::to_utf16string(text); - return true; - } - - template - bool bind_impl(const key_type &text, std::string &ref) - { - ref = utility::conversions::to_utf8string(text); - return true; - } -} }} diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 7590497420..72e13f046c 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -1754,6 +1754,7 @@ class asio_context final : public request_context, public std::enable_shared_fro .then([this_request, read_size, shared_decompressed AND_CAPTURE_MEMBER_FUNCTION_POINTERS]( pplx::task op) { size_t writtenSize = 0; + (void)writtenSize; try { writtenSize = op.get(); diff --git a/Release/src/http/common/http_compression.cpp b/Release/src/http/common/http_compression.cpp index e7e7f9a927..7fc229642d 100644 --- a/Release/src/http/common/http_compression.cpp +++ b/Release/src/http/common/http_compression.cpp @@ -620,7 +620,7 @@ class generic_decompress_factory : public decompress_factory const utility::string_t& algorithm() const { return m_algorithm; } - const uint16_t weight() const { return m_weight; } + uint16_t weight() const { return m_weight; } std::unique_ptr make_decompressor() const { return _make_decompressor(); } @@ -753,6 +753,10 @@ std::unique_ptr make_gzip_compressor(int compressionLevel, in #if defined(CPPREST_HTTP_COMPRESSION) return std::move(std::make_unique(compressionLevel, method, strategy, memLevel)); #else // CPPREST_HTTP_COMPRESSION + (void)compressionLevel; + (void)method; + (void)strategy; + (void)memLevel; return std::unique_ptr(); #endif // CPPREST_HTTP_COMPRESSION } @@ -762,6 +766,10 @@ std::unique_ptr make_deflate_compressor(int compressionLevel, #if defined(CPPREST_HTTP_COMPRESSION) return std::move(std::make_unique(compressionLevel, method, strategy, memLevel)); #else // CPPREST_HTTP_COMPRESSION + (void)compressionLevel; + (void)method; + (void)strategy; + (void)memLevel; return std::unique_ptr(); #endif // CPPREST_HTTP_COMPRESSION } @@ -771,6 +779,9 @@ std::unique_ptr make_brotli_compressor(uint32_t window, uint3 #if defined(CPPREST_HTTP_COMPRESSION) && defined(CPPREST_BROTLI_COMPRESSION) return std::move(std::make_unique(window, quality, mode)); #else // CPPREST_BROTLI_COMPRESSION + (void)window; + (void)quality; + (void)mode; return std::unique_ptr(); #endif // CPPREST_BROTLI_COMPRESSION } @@ -800,7 +811,7 @@ const std::vector> get_decompress_factories( } } // namespace builtin -static bool is_http_whitespace(utility::char_t ch) { return ch == _XPLATSTR(' ') || ch == _XPLATSTR('\t'); } +static bool is_http_whitespace(const utility::char_t ch) { return ch == _XPLATSTR(' ') || ch == _XPLATSTR('\t'); } static void remove_surrounding_http_whitespace(const utility::string_t& encoding, size_t& start, size_t& length) { @@ -1084,7 +1095,7 @@ utility::string_t build_supported_header(header_types type, // Add all specified algorithms and their weights to the header start = true; os.imbue(std::locale::classic()); - for each (auto& factory in f) + for (auto& factory : f) { if (factory) { diff --git a/Release/src/http/common/internal_http_helpers.h b/Release/src/http/common/internal_http_helpers.h index ef19612270..76b4f4f4da 100644 --- a/Release/src/http/common/internal_http_helpers.h +++ b/Release/src/http/common/internal_http_helpers.h @@ -34,7 +34,7 @@ bool validate_method(const utility::string_t& method); namespace web { namespace http { namespace compression { -class compression::decompress_factory; +class decompress_factory; namespace details { namespace builtin { diff --git a/Release/tests/functional/http/client/compression_tests.cpp b/Release/tests/functional/http/client/compression_tests.cpp index e9cc9ef661..ca2215afd9 100644 --- a/Release/tests/functional/http/client/compression_tests.cpp +++ b/Release/tests/functional/http/client/compression_tests.cpp @@ -13,6 +13,7 @@ #include "cpprest/details/http_helpers.h" #include "cpprest/version.h" +#include "cpprest/asyncrt_utils.h" #include "stdafx.h" #include @@ -202,7 +203,7 @@ SUITE(compression_tests) std::vector dcmp_buffer; web::http::compression::operation_result r; std::vector chunk_sizes; - Concurrency::task_group_status result; + pplx::task_status result; size_t csize; size_t dsize; size_t i; @@ -210,8 +211,8 @@ SUITE(compression_tests) if (algorithm == fake_provider::FAKE) { - compressor = std::make_unique(buffer_size); - decompressor = std::make_unique(buffer_size); + compressor = utility::details::make_unique(buffer_size); + decompressor = utility::details::make_unique(buffer_size); } else { @@ -247,7 +248,7 @@ SUITE(compression_tests) web::http::compression::operation_hint::has_more) .then([&r](web::http::compression::operation_result x) { r = x; }) .wait(); - VERIFY_ARE_EQUAL(result, Concurrency::task_group_status::completed); + VERIFY_ARE_EQUAL(result, pplx::task_status::completed); VERIFY_ARE_EQUAL(r.input_bytes_processed, std::min(chunk_size, buffer_size - i)); VERIFY_ARE_EQUAL(r.done, false); chunk_sizes.push_back(r.output_bytes_produced); @@ -272,7 +273,7 @@ SUITE(compression_tests) web::http::compression::operation_hint::is_last) .then([&r](web::http::compression::operation_result x) { r = x; }) .wait(); - VERIFY_ARE_EQUAL(result, Concurrency::task_group_status::completed); + VERIFY_ARE_EQUAL(result, pplx::task_status::completed); VERIFY_ARE_EQUAL(r.input_bytes_processed, 0); chunk_sizes.push_back(r.output_bytes_produced); csize += r.output_bytes_produced; @@ -283,7 +284,7 @@ SUITE(compression_tests) result = compressor->compress(NULL, 0, NULL, 0, web::http::compression::operation_hint::is_last) .then([&r](web::http::compression::operation_result x) { r = x; }) .wait(); - VERIFY_ARE_EQUAL(result, Concurrency::task_group_status::completed); + VERIFY_ARE_EQUAL(result, pplx::task_status::completed); VERIFY_ARE_EQUAL(r.input_bytes_processed, 0); VERIFY_ARE_EQUAL(r.output_bytes_produced, 0); VERIFY_ARE_EQUAL(r.done, true); @@ -311,7 +312,7 @@ SUITE(compression_tests) hint) .then([&r](web::http::compression::operation_result x) { r = x; }) .wait(); - VERIFY_ARE_EQUAL(result, Concurrency::task_group_status::completed); + VERIFY_ARE_EQUAL(result, pplx::task_status::completed); nn += *it; dsize += r.output_bytes_produced; } @@ -339,7 +340,7 @@ SUITE(compression_tests) web::http::compression::operation_hint::has_more) .then([&r](web::http::compression::operation_result x) { r = x; }) .wait(); - VERIFY_ARE_EQUAL(result, Concurrency::task_group_status::completed); + VERIFY_ARE_EQUAL(result, pplx::task_status::completed); dsize += r.output_bytes_produced; nn += r.input_bytes_processed; n -= r.input_bytes_processed; @@ -354,7 +355,7 @@ SUITE(compression_tests) result = decompressor->decompress(NULL, 0, NULL, 0, web::http::compression::operation_hint::has_more) .then([&r](web::http::compression::operation_result x) { r = x; }) .wait(); - VERIFY_ARE_EQUAL(result, Concurrency::task_group_status::completed); + VERIFY_ARE_EQUAL(result, pplx::task_status::completed); VERIFY_ARE_EQUAL(r.input_bytes_processed, 0); VERIFY_ARE_EQUAL(r.output_bytes_produced, 0); VERIFY_IS_TRUE(r.done); @@ -370,7 +371,7 @@ SUITE(compression_tests) web::http::compression::operation_hint::is_last) .then([&r](web::http::compression::operation_result x) { r = x; }) .wait(); - VERIFY_ARE_EQUAL(result, Concurrency::task_group_status::completed); + VERIFY_ARE_EQUAL(result, pplx::task_status::completed); VERIFY_ARE_EQUAL(r.output_bytes_produced, buffer_size); VERIFY_ARE_EQUAL(input_buffer, dcmp_buffer); @@ -448,28 +449,28 @@ SUITE(compression_tests) std::shared_ptr fcf = web::http::compression::make_compress_factory( fake_provider::FAKE, []() -> std::unique_ptr { - return std::make_unique(); + return utility::details::make_unique(); }); std::vector> fcv; fcv.push_back(fcf); std::shared_ptr fdf = web::http::compression::make_decompress_factory( fake_provider::FAKE, 800, []() -> std::unique_ptr { - return std::make_unique(); + return utility::details::make_unique(); }); std::vector> fdv; fdv.push_back(fdf); std::shared_ptr ncf = web::http::compression::make_compress_factory( _NONE, []() -> std::unique_ptr { - return std::make_unique(); + return utility::details::make_unique(); }); std::vector> ncv; ncv.push_back(ncf); std::shared_ptr ndf = web::http::compression::make_decompress_factory( _NONE, 800, []() -> std::unique_ptr { - return std::make_unique(); + return utility::details::make_unique(); }); std::vector> ndv; ndv.push_back(ndf); @@ -794,7 +795,7 @@ SUITE(compression_tests) { test_http_server* p_server = nullptr; std::unique_ptr scoped = - std::move(std::make_unique(m_uri)); + std::move(utility::details::make_unique(m_uri)); scoped->server()->next_request().then([&skip_transfer_put](pplx::task op) { try { @@ -810,7 +811,7 @@ SUITE(compression_tests) http_client client(m_uri); http_request msg(methods::PUT); - msg.set_compressor(std::make_unique(0)); + msg.set_compressor(utility::details::make_unique(0)); msg.set_body(concurrency::streams::rawptr_stream::open_istream((const uint8_t*)nullptr, 0)); http_response rsp = client.request(msg).get(); rsp.content_ready().wait(); @@ -872,7 +873,7 @@ SUITE(compression_tests) if (encoding.find(fake_provider::FAKE) != utility::string_t::npos) { // This one won't be found in the server's default set... - rsp._get_impl()->set_compressor(std::make_unique(buffer_size)); + rsp._get_impl()->set_compressor(utility::details::make_unique(buffer_size)); } #endif // _WIN32 rsp.set_body( @@ -913,7 +914,7 @@ SUITE(compression_tests) } else { - scoped = std::move(std::make_unique(m_uri)); + scoped = std::move(utility::details::make_unique(m_uri)); p_server = scoped->server(); } @@ -968,12 +969,12 @@ SUITE(compression_tests) fake_provider::FAKE, 1000, [buffer_size]() -> std::unique_ptr { - return std::make_unique(buffer_size); + return utility::details::make_unique(buffer_size); }); dfactories.push_back(dmap[fake_provider::FAKE]); cfactories.push_back(web::http::compression::make_compress_factory( fake_provider::FAKE, [buffer_size]() -> std::unique_ptr { - return std::make_unique(buffer_size); + return utility::details::make_unique(buffer_size); })); v.resize(buffer_size); @@ -1037,7 +1038,7 @@ SUITE(compression_tests) if (algorithm == fake_provider::FAKE) { VERIFY_IS_FALSE((bool)c); - c = std::make_unique(buffer_size); + c = utility::details::make_unique(buffer_size); } VERIFY_IS_TRUE((bool)c); auto got = c->compress(v.data(), @@ -1069,7 +1070,7 @@ SUITE(compression_tests) VERIFY_ARE_EQUAL(boo, algorithm != fake_provider::FAKE); if (algorithm == fake_provider::FAKE) { - msg.set_compressor(std::make_unique(buffer_size)); + msg.set_compressor(utility::details::make_unique(buffer_size)); } } else From fba9a5945a166d695c854454d85f3f47a69f9d9e Mon Sep 17 00:00:00 2001 From: copterquad <43890166+copterquad@users.noreply.github.com> Date: Tue, 9 Oct 2018 07:56:45 +0530 Subject: [PATCH 259/438] typo a an -> an (#886) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6b0934320..32374d716a 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Big or small we'd like to take your [contributions](https://github.com/Microsoft ## Having Trouble? -We'd love to get your review score, whether good or bad, but even more than that, we want to fix your problem. If you submit your issue as a Review, we won't be able to respond to your problem and ask any follow-up questions that may be necessary. The most efficient way to do that is to open a an issue in our [issue tracker](https://github.com/Microsoft/cpprestsdk/issues). +We'd love to get your review score, whether good or bad, but even more than that, we want to fix your problem. If you submit your issue as a Review, we won't be able to respond to your problem and ask any follow-up questions that may be necessary. The most efficient way to do that is to open an issue in our [issue tracker](https://github.com/Microsoft/cpprestsdk/issues). ### Quick Links From 98550a4e5db3379db76f1948d5c7c19c2367e3f4 Mon Sep 17 00:00:00 2001 From: Christian <43907599+chris0x44@users.noreply.github.com> Date: Tue, 9 Oct 2018 04:28:31 +0200 Subject: [PATCH 260/438] Correct exception messages and comments in asyncrt_utils (#889) --- Release/src/utilities/asyncrt_utils.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index 3faffd1e40..e971c3c544 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -374,7 +374,7 @@ inline size_t count_utf8_to_utf16(const std::string& s) const char c2{ sData[index++] }; if ((c2 & 0xC0) != BIT8) { - throw std::range_error("UTF-8 continuation byte is missing leading byte"); + throw std::range_error("UTF-8 continuation byte is missing leading bit mask"); } // can't require surrogates for 7FF @@ -391,7 +391,7 @@ inline size_t count_utf8_to_utf16(const std::string& s) const char c3{ sData[index++] }; if (((c2 | c3) & 0xC0) != BIT8) { - throw std::range_error("UTF-8 continuation byte is missing leading byte"); + throw std::range_error("UTF-8 continuation byte is missing leading bit mask"); } result -= 2; @@ -408,7 +408,7 @@ inline size_t count_utf8_to_utf16(const std::string& s) const char c4{ sData[index++] }; if (((c2 | c3 | c4) & 0xC0) != BIT8) { - throw std::range_error("UTF-8 continuation byte is missing leading byte"); + throw std::range_error("UTF-8 continuation byte is missing leading bit mask"); } const uint32_t codePoint = ((c & LOW_3BITS) << 18) | ((c2 & LOW_6BITS) << 12) | ((c3 & LOW_6BITS) << 6) | (c4 & LOW_6BITS); @@ -500,7 +500,7 @@ inline size_t count_utf16_to_utf8(const utf16string &w) } } // Check for high surrogate. - else if (ch >= H_SURROGATE_START && ch <= H_SURROGATE_END) // 4 bytes need using 21 bits + else if (ch >= H_SURROGATE_START && ch <= H_SURROGATE_END) // 4 bytes needed (21 bits used) { ++index; if (index == srcSize) @@ -555,8 +555,8 @@ std::string __cdecl conversions::utf16_to_utf8(const utf16string &w) const auto lowSurrogate = srcData[++index]; // To get from surrogate pair to Unicode code point: - // - subract 0xD800 from high surrogate, this forms top ten bits - // - subract 0xDC00 from low surrogate, this forms low ten bits + // - subtract 0xD800 from high surrogate, this forms top ten bits + // - subtract 0xDC00 from low surrogate, this forms low ten bits // - add 0x10000 // Leaves a code point in U+10000 to U+10FFFF range. uint32_t codePoint = highSurrogate - H_SURROGATE_START; @@ -564,7 +564,7 @@ std::string __cdecl conversions::utf16_to_utf8(const utf16string &w) codePoint |= lowSurrogate - L_SURROGATE_START; codePoint += SURROGATE_PAIR_START; - // 4 bytes need using 21 bits + // 4 bytes needed (21 bits used) destData[destIndex++] = static_cast((codePoint >> 18) | 0xF0); // leading 3 bits destData[destIndex++] = static_cast(((codePoint >> 12) & LOW_6BITS) | BIT8); // next 6 bits destData[destIndex++] = static_cast(((codePoint >> 6) & LOW_6BITS) | BIT8); // next 6 bits @@ -592,6 +592,8 @@ utf16string __cdecl conversions::latin1_to_utf16(const std::string &s) // Latin1 is the first 256 code points in Unicode. // In UTF-16 encoding each of these is represented as exactly the numeric code point. utf16string dest; + // Prefer resize combined with for-loop over constructor dest(s.begin(), s.end()) + // for faster assignment. dest.resize(s.size()); for (size_t i = 0; i < s.size(); ++i) { From 948b70b5b56c5501786e47f5aa95f235f9af4be2 Mon Sep 17 00:00:00 2001 From: mobileben Date: Mon, 8 Oct 2018 19:41:23 -0700 Subject: [PATCH 261/438] Various fixes on #866 which broke building for iOS and Mac (#888) * Various fixes on #866 which broke building for iOS and Mac * Remove trailing semicolon from namespace since flags error when building on Ubuntu * Ubuntu builds needs to factor in unused arguments/variables * Remove trailing spaces from empty lines * Remove duplicate bind_impls. * Fix some merge fallout with master. --- Release/include/cpprest/http_headers.h | 3 +- Release/src/http/common/http_compression.cpp | 35 ++++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Release/include/cpprest/http_headers.h b/Release/include/cpprest/http_headers.h index 3761940c8b..34f0122b3f 100644 --- a/Release/include/cpprest/http_headers.h +++ b/Release/include/cpprest/http_headers.h @@ -18,7 +18,6 @@ #include "cpprest/asyncrt_utils.h" namespace web { namespace http { - /// /// Binds an individual reference to a string value. /// @@ -250,7 +249,7 @@ class http_headers return false; } - return details::bind_impl(iter->second, value) || iter->second.empty(); + return web::http::details::bind_impl(iter->second, value) || iter->second.empty(); } /// diff --git a/Release/src/http/common/http_compression.cpp b/Release/src/http/common/http_compression.cpp index 7fc229642d..194f1efc97 100644 --- a/Release/src/http/common/http_compression.cpp +++ b/Release/src/http/common/http_compression.cpp @@ -156,7 +156,7 @@ class zlib_compressor_base : public compress_provider private: int m_state{Z_BUF_ERROR}; - z_stream m_stream{0}; + z_stream m_stream{}; const utility::string_t& m_algorithm; }; @@ -263,7 +263,7 @@ class zlib_decompressor_base : public decompress_provider private: int m_state{Z_BUF_ERROR}; - z_stream m_stream{0}; + z_stream m_stream{}; const utility::string_t& m_algorithm; }; @@ -283,7 +283,7 @@ class gzip_compressor : public zlib_compressor_base class gzip_decompressor : public zlib_decompressor_base { public: - gzip_decompressor::gzip_decompressor() : zlib_decompressor_base(16) // gzip auto-detect + gzip_decompressor() : zlib_decompressor_base(16) // gzip auto-detect { } }; @@ -634,14 +634,14 @@ class generic_decompress_factory : public decompress_factory static const std::vector> g_compress_factories #if defined(CPPREST_HTTP_COMPRESSION) = {std::make_shared( - algorithm::GZIP, []() -> std::unique_ptr { return std::make_unique(); }), + algorithm::GZIP, []() -> std::unique_ptr { return utility::details::make_unique(); }), std::make_shared( algorithm::DEFLATE, - []() -> std::unique_ptr { return std::make_unique(); }), + []() -> std::unique_ptr { return utility::details::make_unique(); }), #if defined(CPPREST_BROTLI_COMPRESSION) std::make_shared( algorithm::BROTLI, - []() -> std::unique_ptr { return std::make_unique(); }) + []() -> std::unique_ptr { return utility::details::make_unique(); }) #endif // CPPREST_BROTLI_COMPRESSION }; #else // CPPREST_HTTP_COMPRESSION @@ -653,16 +653,16 @@ static const std::vector> g_decompress_facto = {std::make_shared( algorithm::GZIP, 500, - []() -> std::unique_ptr { return std::make_unique(); }), + []() -> std::unique_ptr { return utility::details::make_unique(); }), std::make_shared( algorithm::DEFLATE, 500, - []() -> std::unique_ptr { return std::make_unique(); }), + []() -> std::unique_ptr { return utility::details::make_unique(); }), #if defined(CPPREST_BROTLI_COMPRESSION) std::make_shared( algorithm::BROTLI, 500, - []() -> std::unique_ptr { return std::make_unique(); }) + []() -> std::unique_ptr { return utility::details::make_unique(); }) #endif // CPPREST_BROTLI_COMPRESSION }; #else // CPPREST_HTTP_COMPRESSION @@ -748,10 +748,11 @@ std::shared_ptr get_decompress_factory(const utility::string return std::shared_ptr(); } + std::unique_ptr make_gzip_compressor(int compressionLevel, int method, int strategy, int memLevel) { #if defined(CPPREST_HTTP_COMPRESSION) - return std::move(std::make_unique(compressionLevel, method, strategy, memLevel)); + return utility::details::make_unique(compressionLevel, method, strategy, memLevel); #else // CPPREST_HTTP_COMPRESSION (void)compressionLevel; (void)method; @@ -760,11 +761,11 @@ std::unique_ptr make_gzip_compressor(int compressionLevel, in return std::unique_ptr(); #endif // CPPREST_HTTP_COMPRESSION } - + std::unique_ptr make_deflate_compressor(int compressionLevel, int method, int strategy, int memLevel) { #if defined(CPPREST_HTTP_COMPRESSION) - return std::move(std::make_unique(compressionLevel, method, strategy, memLevel)); + return utility::details::make_unique(compressionLevel, method, strategy, memLevel); #else // CPPREST_HTTP_COMPRESSION (void)compressionLevel; (void)method; @@ -777,7 +778,7 @@ std::unique_ptr make_deflate_compressor(int compressionLevel, std::unique_ptr make_brotli_compressor(uint32_t window, uint32_t quality, uint32_t mode) { #if defined(CPPREST_HTTP_COMPRESSION) && defined(CPPREST_BROTLI_COMPRESSION) - return std::move(std::make_unique(window, quality, mode)); + return utility::details::make_unique(window, quality, mode); #else // CPPREST_BROTLI_COMPRESSION (void)window; (void)quality; @@ -962,7 +963,7 @@ std::unique_ptr get_compressor_from_header( if (compressor) { - return std::move(compressor); + return compressor; } // If we're here, we didn't match the caller's compressor above; @@ -976,7 +977,7 @@ std::unique_ptr get_compressor_from_header( auto compressor = web::http::compression::builtin::_make_compressor(f, coding); if (compressor) { - return std::move(compressor); + return compressor; } if (type == header_types::accept_encoding && utility::details::str_iequal(coding, _XPLATSTR("identity"))) { @@ -1079,7 +1080,7 @@ std::unique_ptr get_decompressor_from_header( // Either the response is compressed and we have a decompressor that can handle it, or // built-in compression is not enabled and we don't have an alternate set of decompressors - return std::move(decompressor); + return decompressor; } utility::string_t build_supported_header(header_types type, @@ -1120,7 +1121,7 @@ utility::string_t build_supported_header(header_types type, os << _XPLATSTR("identity;q=1, *;q=0"); } - return std::move(os.str()); + return os.str(); } } // namespace details } // namespace compression From b211145688802492e4783478e51758156cfc2f59 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Mon, 8 Oct 2018 19:44:59 -0700 Subject: [PATCH 262/438] Fix narrowing conversion warnings on Windows. (#895) --- Release/src/http/client/http_client_winhttp.cpp | 2 +- Release/src/http/common/http_msg.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Release/src/http/client/http_client_winhttp.cpp b/Release/src/http/client/http_client_winhttp.cpp index 0a135d039e..ab415bb8b4 100644 --- a/Release/src/http/client/http_client_winhttp.cpp +++ b/Release/src/http/client/http_client_winhttp.cpp @@ -1583,7 +1583,7 @@ class winhttp_client final : public _http_client_communicator else if (length > p_request_context->m_remaining_to_write) { // The stream grew, but we won't - length = p_request_context->m_remaining_to_write; + length = static_cast(p_request_context->m_remaining_to_write); } do_compress(pplx::task_from_result(length)).then(after_read); diff --git a/Release/src/http/common/http_msg.cpp b/Release/src/http/common/http_msg.cpp index d17d09dcef..7a80017828 100644 --- a/Release/src/http/common/http_msg.cpp +++ b/Release/src/http/common/http_msg.cpp @@ -319,7 +319,7 @@ size_t http_msg_base::_get_stream_length() auto offset = stream.tell(); auto end = stream.seek(0, std::ios_base::end); stream.seek(offset); - return static_cast(end - offset); + return static_cast(end - offset); } return std::numeric_limits::max(); From eadff24ec83e2a3449deabb424ae2104b8fedb31 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Tue, 9 Oct 2018 12:12:53 -0700 Subject: [PATCH 263/438] Harden winrt_encryption slightly and avoid a potential reallocation. (#896) --- Release/src/json/json_parsing.cpp | 2 +- Release/src/utilities/web_utilities.cpp | 61 ++++++++++++++----------- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/Release/src/json/json_parsing.cpp b/Release/src/json/json_parsing.cpp index 13ecb5437c..295bd6e16a 100644 --- a/Release/src/json/json_parsing.cpp +++ b/Release/src/json/json_parsing.cpp @@ -1026,7 +1026,7 @@ std::unique_ptr JSON_Parser::_ParseObject( ::std::sort(elems.begin(), elems.end(), json::object::compare_pairs); } - return std::move(obj); + return obj; error: if (!tkn.m_error) diff --git a/Release/src/utilities/web_utilities.cpp b/Release/src/utilities/web_utilities.cpp index f17b5ab099..7ac9d306a2 100644 --- a/Release/src/utilities/web_utilities.cpp +++ b/Release/src/utilities/web_utilities.cpp @@ -12,6 +12,7 @@ ****/ #include "stdafx.h" +#include #if defined(_WIN32) && !defined(__cplusplus_winrt) #include @@ -92,23 +93,28 @@ plaintext_string winrt_encryption::decrypt() const win32_encryption::win32_encryption(const std::wstring &data) : m_numCharacters(data.size()) { - // Early return because CryptProtectMemory crashs with empty string + // Early return because CryptProtectMemory crashes with empty string if (m_numCharacters == 0) { return; } - const auto dataNumBytes = data.size() * sizeof(std::wstring::value_type); - m_buffer.resize(dataNumBytes); - memcpy_s(m_buffer.data(), m_buffer.size(), data.c_str(), dataNumBytes); - - // Buffer must be a multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE - const auto mod = m_buffer.size() % CRYPTPROTECTMEMORY_BLOCK_SIZE; - if (mod != 0) + if (data.size() > (std::numeric_limits::max)() / sizeof(wchar_t)) { - m_buffer.resize(m_buffer.size() + CRYPTPROTECTMEMORY_BLOCK_SIZE - mod); + throw std::length_error("Encryption string too long"); } - if (!CryptProtectMemory(m_buffer.data(), static_cast(m_buffer.size()), CRYPTPROTECTMEMORY_SAME_PROCESS)) + + const auto dataSizeDword = static_cast(data.size() * sizeof(wchar_t)); + + // Round up dataSizeDword to be a multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE + static_assert(CRYPTPROTECTMEMORY_BLOCK_SIZE == 16, "Power of 2 assumptions in this bit masking violated"); + const auto mask = static_cast(CRYPTPROTECTMEMORY_BLOCK_SIZE - 1u); + const auto dataNumBytes = (dataSizeDword & ~mask) + ((dataSizeDword & mask) != 0) * CRYPTPROTECTMEMORY_BLOCK_SIZE; + assert((dataNumBytes % CRYPTPROTECTMEMORY_BLOCK_SIZE) == 0); + assert(dataNumBytes >= dataSizeDword); + m_buffer.resize(dataNumBytes); + memcpy_s(m_buffer.data(), m_buffer.size(), data.c_str(), dataNumBytes); + if (!CryptProtectMemory(m_buffer.data(), dataNumBytes, CRYPTPROTECTMEMORY_SAME_PROCESS)) { throw ::utility::details::create_system_error(GetLastError()); } @@ -121,20 +127,25 @@ win32_encryption::~win32_encryption() plaintext_string win32_encryption::decrypt() const { - if (m_buffer.empty()) - return plaintext_string(new std::wstring()); - // Copy the buffer and decrypt to avoid having to re-encrypt. - auto data = plaintext_string(new std::wstring(reinterpret_cast(m_buffer.data()), m_buffer.size() / 2)); - if (!CryptUnprotectMemory( - const_cast(data->c_str()), - static_cast(m_buffer.size()), - CRYPTPROTECTMEMORY_SAME_PROCESS)) - { - throw ::utility::details::create_system_error(GetLastError()); + auto result = plaintext_string(new std::wstring( + reinterpret_cast(m_buffer.data()), m_buffer.size() / sizeof(wchar_t))); + auto& data = *result; + if (!m_buffer.empty()) { + if (!CryptUnprotectMemory( + &data[0], + static_cast(m_buffer.size()), + CRYPTPROTECTMEMORY_SAME_PROCESS)) + { + throw ::utility::details::create_system_error(GetLastError()); + } + + assert(m_numCharacters <= m_buffer.size()); + SecureZeroMemory(&data[m_numCharacters], data.size() - m_numCharacters); + data.erase(m_numCharacters); } - data->resize(m_numCharacters); - return std::move(data); + + return result; } #endif #endif @@ -143,12 +154,10 @@ void zero_memory_deleter::operator()(::utility::string_t *data) const { CASABLANCA_UNREFERENCED_PARAMETER(data); #if defined(_WIN32) - SecureZeroMemory( - const_cast<::utility::string_t::value_type *>(data->data()), - data->size() * sizeof(::utility::string_t::value_type)); + SecureZeroMemory(&(*data)[0], data->size() * sizeof(::utility::string_t::value_type)); delete data; #endif } } -} \ No newline at end of file +} From 40eb6d22d06fc7efa545c30f4a9473aab8cc0d6e Mon Sep 17 00:00:00 2001 From: Juan Eugenio Abadie Date: Tue, 9 Oct 2018 16:25:45 -0300 Subject: [PATCH 264/438] Remove unused variables to avoid warnings in some compilers (#855) --- Release/include/cpprest/base_uri.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Release/include/cpprest/base_uri.h b/Release/include/cpprest/base_uri.h index b5fc8fcfd0..687844dbb4 100644 --- a/Release/include/cpprest/base_uri.h +++ b/Release/include/cpprest/base_uri.h @@ -29,8 +29,8 @@ namespace web { { uri_components() : m_path(_XPLATSTR("/")), m_port(-1) {} - uri_components(const uri_components &other) = default; - uri_components & operator=(const uri_components &other) = default; + uri_components(const uri_components &) = default; + uri_components & operator=(const uri_components &) = default; // This is for VS2013 compatibility -- replace with '= default' when VS2013 is completely dropped. uri_components(uri_components &&other) CPPREST_NOEXCEPT : @@ -209,12 +209,12 @@ namespace web { /// /// Copy constructor. /// - uri(const uri &other) = default; + uri(const uri &) = default; /// /// Copy assignment operator. /// - uri & operator=(const uri &other) = default; + uri & operator=(const uri &) = default; /// /// Move constructor. From 81eb4cfc5c3645c10d025507ba22677cf4037abc Mon Sep 17 00:00:00 2001 From: Christian <43907599+chris0x44@users.noreply.github.com> Date: Tue, 9 Oct 2018 21:36:41 +0200 Subject: [PATCH 265/438] Enable multi-processor compilation (#890) --- Release/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt index 00fa7a7d11..4bf08ef820 100644 --- a/Release/CMakeLists.txt +++ b/Release/CMakeLists.txt @@ -204,6 +204,11 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") set(WARNINGS) set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4264") add_compile_options(/bigobj) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MP") + set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MP") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MP") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MP") + if (WINDOWS_STORE OR WINDOWS_PHONE) add_compile_options(/ZW) endif() From 2aa4a641b61c6d9d805c7a85b649671d4b55cd27 Mon Sep 17 00:00:00 2001 From: Christian <43907599+chris0x44@users.noreply.github.com> Date: Tue, 9 Oct 2018 23:20:23 +0200 Subject: [PATCH 266/438] Enable precompiled headers for test/functional (#891) --- Release/tests/functional/http/client/CMakeLists.txt | 13 +++++++++++++ Release/tests/functional/json/CMakeLists.txt | 13 +++++++++++++ .../tests/functional/pplx/pplx_test/CMakeLists.txt | 13 +++++++++++++ Release/tests/functional/streams/CMakeLists.txt | 13 +++++++++++++ Release/tests/functional/uri/CMakeLists.txt | 13 +++++++++++++ Release/tests/functional/utils/CMakeLists.txt | 13 +++++++++++++ 6 files changed, 78 insertions(+) diff --git a/Release/tests/functional/http/client/CMakeLists.txt b/Release/tests/functional/http/client/CMakeLists.txt index 17cf4eff81..1cf9b6e6f5 100644 --- a/Release/tests/functional/http/client/CMakeLists.txt +++ b/Release/tests/functional/http/client/CMakeLists.txt @@ -32,6 +32,19 @@ else() target_link_libraries(httpclient_test PRIVATE httptest_utilities) endif() +if(MSVC) + get_target_property(_srcs httpclient_test SOURCES) + + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") + set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") + set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") + endif() + + set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") + target_sources(httpclient_test PRIVATE stdafx.cpp) + target_compile_options(httpclient_test PRIVATE /Yustdafx.h /Zm200) +endif() + if(NOT WIN32) cpprest_find_boost() target_link_libraries(httpclient_test PRIVATE cpprestsdk_boost_internal) diff --git a/Release/tests/functional/json/CMakeLists.txt b/Release/tests/functional/json/CMakeLists.txt index 379a6bd4bf..c9dccfcfeb 100644 --- a/Release/tests/functional/json/CMakeLists.txt +++ b/Release/tests/functional/json/CMakeLists.txt @@ -16,3 +16,16 @@ if(UNIX AND NOT APPLE) cpprest_find_boost() target_link_libraries(json_test PRIVATE cpprestsdk_boost_internal) endif() + +if(MSVC) + get_target_property(_srcs json_test SOURCES) + + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") + set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") + set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") + endif() + + set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") + target_sources(json_test PRIVATE stdafx.cpp) + target_compile_options(json_test PRIVATE /Yustdafx.h /Zm200) +endif() diff --git a/Release/tests/functional/pplx/pplx_test/CMakeLists.txt b/Release/tests/functional/pplx/pplx_test/CMakeLists.txt index 01c56f7522..a51776989b 100644 --- a/Release/tests/functional/pplx/pplx_test/CMakeLists.txt +++ b/Release/tests/functional/pplx/pplx_test/CMakeLists.txt @@ -6,3 +6,16 @@ set(SOURCES ) add_casablanca_test(pplx_test SOURCES) + +if(MSVC) + get_target_property(_srcs pplx_test SOURCES) + + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") + set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") + set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") + endif() + + set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") + target_sources(pplx_test PRIVATE stdafx.cpp) + target_compile_options(pplx_test PRIVATE /Yustdafx.h /Zm200) +endif() diff --git a/Release/tests/functional/streams/CMakeLists.txt b/Release/tests/functional/streams/CMakeLists.txt index 4b11173b18..d2b6858f15 100644 --- a/Release/tests/functional/streams/CMakeLists.txt +++ b/Release/tests/functional/streams/CMakeLists.txt @@ -24,3 +24,16 @@ if(NOT WIN32 OR CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") target_include_directories(streams_test PRIVATE $) endif() endif() + +if(MSVC) + get_target_property(_srcs streams_test SOURCES) + + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") + set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") + set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") + endif() + + set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") + target_sources(streams_test PRIVATE stdafx.cpp) + target_compile_options(streams_test PRIVATE /Yustdafx.h /Zm200) +endif() diff --git a/Release/tests/functional/uri/CMakeLists.txt b/Release/tests/functional/uri/CMakeLists.txt index f869e24d18..86cd0e867a 100644 --- a/Release/tests/functional/uri/CMakeLists.txt +++ b/Release/tests/functional/uri/CMakeLists.txt @@ -12,3 +12,16 @@ set(SOURCES ) add_casablanca_test(uri_test SOURCES) + +if(MSVC) + get_target_property(_srcs uri_test SOURCES) + + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") + set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") + set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") + endif() + + set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") + target_sources(uri_test PRIVATE stdafx.cpp) + target_compile_options(uri_test PRIVATE /Yustdafx.h /Zm200) +endif() diff --git a/Release/tests/functional/utils/CMakeLists.txt b/Release/tests/functional/utils/CMakeLists.txt index ff175283f8..ff5d4cb49c 100644 --- a/Release/tests/functional/utils/CMakeLists.txt +++ b/Release/tests/functional/utils/CMakeLists.txt @@ -13,3 +13,16 @@ add_casablanca_test(utils_test SOURCES) if(CMAKE_COMPILER_IS_GNUCXX) target_compile_options(utils_test PRIVATE "-Wno-deprecated-declarations") endif() + +if(MSVC) + get_target_property(_srcs utils_test SOURCES) + + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") + set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") + set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") + endif() + + set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") + target_sources(utils_test PRIVATE stdafx.cpp) + target_compile_options(utils_test PRIVATE /Yustdafx.h /Zm200) +endif() From 19c9f1c602efbc754d11890ba8e86afc2a8ba138 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Tue, 9 Oct 2018 16:51:40 -0700 Subject: [PATCH 267/438] Add Ubuntu 16.04 Azure Pipelines Validation (#898) --- azure-pipelines.yml | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 azure-pipelines.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000000..dab028e6fa --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,41 @@ +# CppRestSdk Azure Pipelines Configuration + +jobs: + - job: Ubuntu_1604_Apt_Debug + pool: + vmImage: 'Ubuntu 16.04' + steps: + - script: | + sudo apt-get install -y ppa-purge + sudo ppa-purge -y ppa:ondrej/php + sudo apt-get install -y libboost-atomic-dev libboost-thread-dev libboost-system-dev libboost-date-time-dev libboost-regex-dev libboost-filesystem-dev libboost-random-dev libboost-chrono-dev libboost-serialization-dev libwebsocketpp-dev brotli openssl libssl-dev ninja-build + displayName: Apt install dependencies + - script: mkdir build.debug + displayName: Make build.debug + - task: CMake@1 + inputs: + workingDirectory: 'build.debug' + cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Debug ..' + - script: | + cd build.debug + ninja -j 2 + displayName: 'Run ninja' + - job: Ubuntu_1604_Apt_Release + pool: + vmImage: 'Ubuntu 16.04' + steps: + - script: | + sudo apt-get install -y ppa-purge + sudo ppa-purge -y ppa:ondrej/php + sudo apt-get install -y libboost-atomic-dev libboost-thread-dev libboost-system-dev libboost-date-time-dev libboost-regex-dev libboost-filesystem-dev libboost-random-dev libboost-chrono-dev libboost-serialization-dev libwebsocketpp-dev brotli openssl libssl-dev ninja-build + displayName: Apt install dependencies + - script: mkdir build.release + displayName: Make build.release + - task: CMake@1 + inputs: + workingDirectory: 'build.release' + cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Release ..' + - script: | + cd build.release + ninja -j 2 + displayName: 'Run ninja' From 625c666eb6b6002793dd77e3f70eda10c83d5f8e Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Tue, 9 Oct 2018 16:58:10 -0700 Subject: [PATCH 268/438] Add Azure Pipelines badge. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 32374d716a..6739483ebf 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ The C++ REST SDK is a Microsoft project for cloud-based client-server communicat [![openSUSE Tumbleweed package](https://repology.org/badge/version-for-repo/opensuse_tumbleweed/cpprestsdk.svg)](https://repology.org/metapackage/cpprestsdk)
[![Debian Testing package](https://repology.org/badge/version-for-repo/debian_testing/cpprestsdk.svg)](https://repology.org/metapackage/cpprestsdk)
+[![Build Status](https://dev.azure.com/vclibs/cpprestsdk/_apis/build/status/Microsoft.cpprestsdk.Ubuntu)](https://dev.azure.com/vclibs/cpprestsdk/_build/latest?definitionId=1) + With [vcpkg](https://github.com/Microsoft/vcpkg) on Windows ``` PS> vcpkg install cpprestsdk cpprestsdk:x64-windows From b0ebae3591c7e407feeb289202340d1842c87c8a Mon Sep 17 00:00:00 2001 From: paul Date: Thu, 11 Oct 2018 01:05:37 +0300 Subject: [PATCH 269/438] Added URI resolution according to RFC3986 (#897) Added URI resolution according to RFC3986, Section 5 (https://tools.ietf.org/html/rfc3986#section-5) --- Release/include/cpprest/base_uri.h | 12 +- Release/src/uri/uri.cpp | 123 +++++++++++++++++- Release/tests/functional/uri/CMakeLists.txt | 1 + .../functional/uri/resolve_uri_tests.cpp | 68 ++++++++++ 4 files changed, 195 insertions(+), 9 deletions(-) create mode 100644 Release/tests/functional/uri/resolve_uri_tests.cpp diff --git a/Release/include/cpprest/base_uri.h b/Release/include/cpprest/base_uri.h index 687844dbb4..9448bb5d35 100644 --- a/Release/include/cpprest/base_uri.h +++ b/Release/include/cpprest/base_uri.h @@ -379,12 +379,20 @@ namespace web { /// /// Returns the full (encoded) URI as a string. /// - /// The full encoded URI string. + /// The full encoded URI string. utility::string_t to_string() const { return m_uri; } + /// + /// Returns an URI resolved against this as the base URI + /// according to RFC3986, Section 5 (https://tools.ietf.org/html/rfc3986#section-5). + /// + /// The relative URI to be resolved against this as base. + /// The new resolved URI string. + _ASYNCRTIMP utility::string_t resolve_uri(const utility::string_t &relativeUri) const; + _ASYNCRTIMP bool operator == (const uri &other) const; bool operator < (const uri &other) const @@ -413,4 +421,4 @@ namespace web { details::uri_components m_components; }; -} // namespace web +} // namespace web diff --git a/Release/src/uri/uri.cpp b/Release/src/uri/uri.cpp index 737ed12e1b..1953564a9f 100644 --- a/Release/src/uri/uri.cpp +++ b/Release/src/uri/uri.cpp @@ -19,6 +19,9 @@ namespace web { namespace details { namespace { + const ::utility::string_t dotSegment = _XPLATSTR("."); + const ::utility::string_t dotDotSegment = _XPLATSTR(".."); + /// /// Unreserved characters are those that are allowed in a URI but do not have a reserved purpose. They include: /// - A-Z @@ -423,7 +426,60 @@ namespace return encoded; } -} + // 5.2.3. Merge Paths https://tools.ietf.org/html/rfc3986#section-5.2.3 + utility::string_t mergePaths(const utility::string_t &base, const utility::string_t &relative) + { + const auto lastSlash = base.rfind(_XPLATSTR('/')); + if (lastSlash == utility::string_t::npos) + { + return base + _XPLATSTR('/') + relative; + } + else if (lastSlash == base.size() - 1) + { + return base + relative; + } + // path contains and does not end with '/', we remove segment after last '/' + return base.substr(0, lastSlash + 1) + relative; + } + + // 5.2.4. Remove Dot Segments https://tools.ietf.org/html/rfc3986#section-5.2.4 + void removeDotSegments(uri_builder &builder) + { + if (builder.path().find(_XPLATSTR('.')) == utility::string_t::npos) + return; + + const auto segments = uri::split_path(builder.path()); + std::vector> result; + for (auto& segment : segments) + { + if (segment == dotSegment) + continue; + else if (segment != dotDotSegment) + result.push_back(segment); + else if (!result.empty()) + result.pop_back(); + } + if (result.empty()) + { + builder.set_path(utility::string_t()); + return; + } + utility::string_t path = result.front().get(); + for (size_t i = 1; i != result.size(); ++i) + { + path += _XPLATSTR('/'); + path += result[i].get(); + } + if (segments.back() == dotDotSegment + || segments.back() == dotSegment + || builder.path().back() == _XPLATSTR('/')) + { + path += _XPLATSTR('/'); + } + + builder.set_path(std::move(path)); + } +} // namespace utility::string_t uri_components::join() { @@ -448,7 +504,8 @@ utility::string_t uri_components::join() if (!m_scheme.empty()) { - ret.append(m_scheme).append({ _XPLATSTR(':') }); + ret.append(m_scheme); + ret.push_back(_XPLATSTR(':')); } if (!m_host.empty()) @@ -473,7 +530,7 @@ utility::string_t uri_components::join() // only add the leading slash when the host is present if (!m_host.empty() && m_path.front() != _XPLATSTR('/')) { - ret.append({ _XPLATSTR('/') }); + ret.push_back(_XPLATSTR('/')); } ret.append(m_path); @@ -481,17 +538,19 @@ utility::string_t uri_components::join() if (!m_query.empty()) { - ret.append({ _XPLATSTR('?') }).append(m_query); + ret.push_back(_XPLATSTR('?')); + ret.append(m_query); } if (!m_fragment.empty()) { - ret.append({ _XPLATSTR('#') }).append(m_fragment); + ret.push_back(_XPLATSTR('#')); + ret.append(m_fragment); } return ret; } -} +} // namespace details uri::uri(const details::uri_components &components) : m_components(components) { @@ -715,7 +774,7 @@ std::map uri::split_query(const utility::s utility::string_t key(key_value_pair.begin(), key_value_pair.begin() + equals_index); utility::string_t value(key_value_pair.begin() + equals_index + 1, key_value_pair.end()); results[key] = value; - } + } } return results; @@ -784,4 +843,54 @@ bool uri::operator == (const uri &other) const return true; } +//resolving URI according to RFC3986, Section 5 https://tools.ietf.org/html/rfc3986#section-5 +utility::string_t uri::resolve_uri(const utility::string_t &relativeUri) const +{ + if (relativeUri.empty()) + { + return to_string(); + } + + if (relativeUri[0] == _XPLATSTR('/')) // starts with '/' + { + if (relativeUri.size() >= 2 && relativeUri[1] == _XPLATSTR('/')) // starts with '//' + { + return this->scheme() + _XPLATSTR(':') + relativeUri; + } + + // otherwise relative to root + auto builder = uri_builder(this->authority()); + builder.append(relativeUri); + details::removeDotSegments(builder); + return builder.to_string(); + } + + const auto url = uri(relativeUri); + if (!url.scheme().empty()) + return relativeUri; + + if (!url.authority().is_empty()) + { + return uri_builder(url).set_scheme(this->scheme()).to_string(); + } + + // relative url + auto builder = uri_builder(*this); + if (url.path() == _XPLATSTR("/") || url.path().empty()) // web::uri considers empty path as '/' + { + if (!url.query().empty()) + { + builder.set_query(url.query()); + } + } + else if (!this->path().empty()) + { + builder.set_path(details::mergePaths(this->path(), url.path())); + details::removeDotSegments(builder); + builder.set_query(url.query()); + } + + return builder.set_fragment(url.fragment()).to_string(); } + +} // namespace web diff --git a/Release/tests/functional/uri/CMakeLists.txt b/Release/tests/functional/uri/CMakeLists.txt index 86cd0e867a..1a4aaee947 100644 --- a/Release/tests/functional/uri/CMakeLists.txt +++ b/Release/tests/functional/uri/CMakeLists.txt @@ -8,6 +8,7 @@ set(SOURCES operator_tests.cpp splitting_tests.cpp uri_builder_tests.cpp + resolve_uri_tests.cpp stdafx.cpp ) diff --git a/Release/tests/functional/uri/resolve_uri_tests.cpp b/Release/tests/functional/uri/resolve_uri_tests.cpp new file mode 100644 index 0000000000..963be8656f --- /dev/null +++ b/Release/tests/functional/uri/resolve_uri_tests.cpp @@ -0,0 +1,68 @@ +#include "stdafx.h" + +using namespace web; +using namespace utility; + +namespace tests { namespace functional { namespace uri_tests { + +//testing resolution against examples from Section 5.4 https://tools.ietf.org/html/rfc3986#section-5.4 +SUITE(resolve_uri_tests) +{ +//5.4.1. Normal Examples https://tools.ietf.org/html/rfc3986#section-5.4.1 +TEST(resolve_uri_normal) +{ + const uri baseUri = U("http://a/b/c/d;p?q"); + + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g:h")), U("g:h")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g")), U("http://a/b/c/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("./g")), U("http://a/b/c/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g/")), U("http://a/b/c/g/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("/g")), U("http://a/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("//g")), U("http://g/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("?y")), U("http://a/b/c/d;p?y")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g?y")), U("http://a/b/c/g?y")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("#s")), U("http://a/b/c/d;p?q#s")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g#s")), U("http://a/b/c/g#s")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g?y#s")), U("http://a/b/c/g?y#s")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U(";x")), U("http://a/b/c/;x")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g;x")), U("http://a/b/c/g;x")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g;x?y#s")), U("http://a/b/c/g;x?y#s")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("")), U("http://a/b/c/d;p?q")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U(".")), U("http://a/b/c/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("./")), U("http://a/b/c/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("..")), U("http://a/b/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../")), U("http://a/b/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../g")), U("http://a/b/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../..")), U("http://a/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../../")), U("http://a/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../../g")), U("http://a/g")); +} +//5.4.2. Abnormal Examples https://tools.ietf.org/html/rfc3986#section-5.4.2 +TEST(resolve_uri_abnormal) +{ + const uri baseUri = U("http://a/b/c/d;p?q"); + + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../../../g")), U("http://a/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("../../../../g")), U("http://a/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("/./g")), U("http://a/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("/../g")), U("http://a/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g.")), U("http://a/b/c/g.")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U(".g")), U("http://a/b/c/.g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g..")), U("http://a/b/c/g..")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("..g")), U("http://a/b/c/..g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("./../g")), U("http://a/b/g")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("./g/.")), U("http://a/b/c/g/")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g/./h")), U("http://a/b/c/g/h")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g/../h")), U("http://a/b/c/h")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g;x=1/./y")), U("http://a/b/c/g;x=1/y")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g;x=1/../y")), U("http://a/b/c/y")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g?y/./x")), U("http://a/b/c/g?y/./x")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g?y/../x")), U("http://a/b/c/g?y/../x")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g#s/./x")), U("http://a/b/c/g#s/./x")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("g#s/../x")), U("http://a/b/c/g#s/../x")); + VERIFY_ARE_EQUAL(baseUri.resolve_uri(U("http:g")), U("http:g")); +} + +} // SUITE(resolve_uri_tests) + +}}} From c6377e933e2d3a73de5b467ad292b4b7e3d8ec0a Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Wed, 10 Oct 2018 15:40:26 -0700 Subject: [PATCH 270/438] Add MacOS pipelines build support. (#902) * Attempt to add MacOS pipelines support; increase parallelism to 4. * Fix "expression unused" warnings on MacOS. --- .../http/client/compression_tests.cpp | 8 ++--- azure-pipelines.yml | 36 +++++++++++++++++-- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/Release/tests/functional/http/client/compression_tests.cpp b/Release/tests/functional/http/client/compression_tests.cpp index ca2215afd9..256c174c69 100644 --- a/Release/tests/functional/http/client/compression_tests.cpp +++ b/Release/tests/functional/http/client/compression_tests.cpp @@ -761,15 +761,15 @@ SUITE(compression_tests) // No acquire(), to force non-acquire compression client codepaths virtual bool acquire(_Out_ _CharType*& ptr, _Out_ size_t& count) { - ptr; - count; + (void)ptr; + (void)count; return false; } virtual void release(_Out_writes_(count) _CharType* ptr, _In_ size_t count) { - ptr; - count; + (void)ptr; + (void)count; } static concurrency::streams::basic_istream<_CharType> open_istream(const _CharType* data, size_t size) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index dab028e6fa..f49e5ecdbc 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -18,7 +18,7 @@ jobs: cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Debug ..' - script: | cd build.debug - ninja -j 2 + ninja -j 4 displayName: 'Run ninja' - job: Ubuntu_1604_Apt_Release pool: @@ -37,5 +37,37 @@ jobs: cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Release ..' - script: | cd build.release - ninja -j 2 + ninja -j 4 + displayName: 'Run ninja' + - job: MacOS_Debug + pool: + vmImage: 'macOS-10.13' + steps: + - script: brew install boost openssl ninja + displayName: Berw install dependencies + - script: mkdir build.debug + displayName: Make build.debug + - task: CMake@1 + inputs: + workingDirectory: 'build.debug' + cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Debug ..' + - script: | + cd build.debug + ninja -j 4 + displayName: 'Run ninja' + - job: MacOS_Release + pool: + vmImage: 'macOS-10.13' + steps: + - script: brew install boost openssl ninja + displayName: Berw install dependencies + - script: mkdir build.release + displayName: Make build.release + - task: CMake@1 + inputs: + workingDirectory: 'build.release' + cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Release ..' + - script: | + cd build.release + ninja -j 4 displayName: 'Run ninja' From 10494918aabd47b0d16181a6717f582e3ce65a67 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Wed, 10 Oct 2018 17:00:20 -0700 Subject: [PATCH 271/438] Adding test runs to Azure Pipelines. (#899) * Adding test runs to Pipelines. * Use get instead of then/wait in compression tests. * Fix typo to not write to *done. * Use dylib on MacOS. --- .../http/client/compression_tests.cpp | 88 +++++++------------ azure-pipelines.yml | 16 ++++ 2 files changed, 46 insertions(+), 58 deletions(-) diff --git a/Release/tests/functional/http/client/compression_tests.cpp b/Release/tests/functional/http/client/compression_tests.cpp index 256c174c69..10e37186fa 100644 --- a/Release/tests/functional/http/client/compression_tests.cpp +++ b/Release/tests/functional/http/client/compression_tests.cpp @@ -62,7 +62,7 @@ SUITE(compression_tests) if (_done) { input_bytes_processed = 0; - if (*done) + if (done) { *done = true; } @@ -127,7 +127,7 @@ SUITE(compression_tests) if (_done) { input_bytes_processed = 0; - if (*done) + if (done) { *done = true; } @@ -203,7 +203,6 @@ SUITE(compression_tests) std::vector dcmp_buffer; web::http::compression::operation_result r; std::vector chunk_sizes; - pplx::task_status result; size_t csize; size_t dsize; size_t i; @@ -240,15 +239,11 @@ SUITE(compression_tests) cmp_buffer.resize(buffer_size); // pessimistic (or not, for non-compressible data) for (i = 0; i < buffer_size; i += chunk_size) { - result = compressor - ->compress(input_buffer.data() + i, - std::min(chunk_size, buffer_size - i), - cmp_buffer.data() + csize, - std::min(chunk_size, buffer_size - csize), - web::http::compression::operation_hint::has_more) - .then([&r](web::http::compression::operation_result x) { r = x; }) - .wait(); - VERIFY_ARE_EQUAL(result, pplx::task_status::completed); + r = compressor->compress(input_buffer.data() + i, + std::min(chunk_size, buffer_size - i), + cmp_buffer.data() + csize, + std::min(chunk_size, buffer_size - csize), + web::http::compression::operation_hint::has_more).get(); VERIFY_ARE_EQUAL(r.input_bytes_processed, std::min(chunk_size, buffer_size - i)); VERIFY_ARE_EQUAL(r.done, false); chunk_sizes.push_back(r.output_bytes_produced); @@ -265,15 +260,11 @@ SUITE(compression_tests) cmpsize += std::min(chunk_size, (size_t)200); cmp_buffer.resize(cmpsize); } - result = compressor - ->compress(NULL, + r = compressor->compress(NULL, 0, cmp_buffer.data() + csize, std::min(chunk_size, cmpsize - csize), - web::http::compression::operation_hint::is_last) - .then([&r](web::http::compression::operation_result x) { r = x; }) - .wait(); - VERIFY_ARE_EQUAL(result, pplx::task_status::completed); + web::http::compression::operation_hint::is_last).get(); VERIFY_ARE_EQUAL(r.input_bytes_processed, 0); chunk_sizes.push_back(r.output_bytes_produced); csize += r.output_bytes_produced; @@ -281,14 +272,12 @@ SUITE(compression_tests) VERIFY_ARE_EQUAL(r.done, true); // once more with no input, to assure no error and done - result = compressor->compress(NULL, 0, NULL, 0, web::http::compression::operation_hint::is_last) - .then([&r](web::http::compression::operation_result x) { r = x; }) - .wait(); - VERIFY_ARE_EQUAL(result, pplx::task_status::completed); + r = compressor->compress(NULL, 0, NULL, 0, web::http::compression::operation_hint::is_last).get(); VERIFY_ARE_EQUAL(r.input_bytes_processed, 0); VERIFY_ARE_EQUAL(r.output_bytes_produced, 0); VERIFY_ARE_EQUAL(r.done, true); } + cmp_buffer.resize(csize); // actual // decompress in as-compressed chunks @@ -304,15 +293,12 @@ SUITE(compression_tests) { hint = web::http::compression::operation_hint::is_last; } - result = decompressor - ->decompress(cmp_buffer.data() + nn, - *it, - dcmp_buffer.data() + dsize, - std::min(chunk_size, buffer_size - dsize), - hint) - .then([&r](web::http::compression::operation_result x) { r = x; }) - .wait(); - VERIFY_ARE_EQUAL(result, pplx::task_status::completed); + + r = decompressor->decompress(cmp_buffer.data() + nn, + *it, + dcmp_buffer.data() + dsize, + std::min(chunk_size, buffer_size - dsize), + hint).get(); nn += *it; dsize += r.output_bytes_produced; } @@ -332,15 +318,11 @@ SUITE(compression_tests) size_t n = std::min(chunk_size, csize - nn); do { - result = decompressor - ->decompress(cmp_buffer.data() + nn, - n, - dcmp_buffer.data() + dsize, - std::min(chunk_size, buffer_size - dsize), - web::http::compression::operation_hint::has_more) - .then([&r](web::http::compression::operation_result x) { r = x; }) - .wait(); - VERIFY_ARE_EQUAL(result, pplx::task_status::completed); + r = decompressor->decompress(cmp_buffer.data() + nn, + n, + dcmp_buffer.data() + dsize, + std::min(chunk_size, buffer_size - dsize), + web::http::compression::operation_hint::has_more).get(); dsize += r.output_bytes_produced; nn += r.input_bytes_processed; n -= r.input_bytes_processed; @@ -352,10 +334,7 @@ SUITE(compression_tests) VERIFY_IS_TRUE(r.done); // once more with no input, to assure no error and done - result = decompressor->decompress(NULL, 0, NULL, 0, web::http::compression::operation_hint::has_more) - .then([&r](web::http::compression::operation_result x) { r = x; }) - .wait(); - VERIFY_ARE_EQUAL(result, pplx::task_status::completed); + r = decompressor->decompress(NULL, 0, NULL, 0, web::http::compression::operation_hint::has_more).get(); VERIFY_ARE_EQUAL(r.input_bytes_processed, 0); VERIFY_ARE_EQUAL(r.output_bytes_produced, 0); VERIFY_IS_TRUE(r.done); @@ -363,15 +342,11 @@ SUITE(compression_tests) // decompress all at once decompressor->reset(); memset(dcmp_buffer.data(), 0, dcmp_buffer.size()); - result = decompressor - ->decompress(cmp_buffer.data(), - csize, - dcmp_buffer.data(), - dcmp_buffer.size(), - web::http::compression::operation_hint::is_last) - .then([&r](web::http::compression::operation_result x) { r = x; }) - .wait(); - VERIFY_ARE_EQUAL(result, pplx::task_status::completed); + r = decompressor->decompress(cmp_buffer.data(), + csize, + dcmp_buffer.data(), + dcmp_buffer.size(), + web::http::compression::operation_hint::is_last).get(); VERIFY_ARE_EQUAL(r.output_bytes_produced, buffer_size); VERIFY_ARE_EQUAL(input_buffer, dcmp_buffer); @@ -385,14 +360,11 @@ SUITE(compression_tests) nn = 0; try { - result = decompressor - ->decompress(cmp_buffer.data(), + r = decompressor->decompress(cmp_buffer.data(), csize, dcmp_buffer.data(), dcmp_buffer.size(), - web::http::compression::operation_hint::is_last) - .then([&nn](web::http::compression::operation_result x) { nn++; }) - .wait(); + web::http::compression::operation_hint::is_last).get(); nn++; } catch (std::runtime_error) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f49e5ecdbc..d984c4094e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -20,6 +20,10 @@ jobs: cd build.debug ninja -j 4 displayName: 'Run ninja' + - script: | + cd build.debug/Release/Binaries + ./test_runner *test.so + displayName: 'Run Tests' - job: Ubuntu_1604_Apt_Release pool: vmImage: 'Ubuntu 16.04' @@ -39,6 +43,10 @@ jobs: cd build.release ninja -j 4 displayName: 'Run ninja' + - script: | + cd build.release/Release/Binaries + ./test_runner *test.so + displayName: 'Run Tests' - job: MacOS_Debug pool: vmImage: 'macOS-10.13' @@ -55,6 +63,10 @@ jobs: cd build.debug ninja -j 4 displayName: 'Run ninja' + - script: | + cd build.debug/Release/Binaries + ./test_runner *test.dylib + displayName: 'Run Tests' - job: MacOS_Release pool: vmImage: 'macOS-10.13' @@ -71,3 +83,7 @@ jobs: cd build.release ninja -j 4 displayName: 'Run ninja' + - script: | + cd build.release/Release/Binaries + ./test_runner *test.dylib + displayName: 'Run Tests' From 5a9f3bc25714dfbfea7fd006085a1f18ee6acde2 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 10 Oct 2018 17:27:48 -0700 Subject: [PATCH 272/438] Move dotSegment and dotDotSegment back into local variables, as suggested by @toughengineer --- Release/src/uri/uri.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Release/src/uri/uri.cpp b/Release/src/uri/uri.cpp index 1953564a9f..fac048c9da 100644 --- a/Release/src/uri/uri.cpp +++ b/Release/src/uri/uri.cpp @@ -19,9 +19,6 @@ namespace web { namespace details { namespace { - const ::utility::string_t dotSegment = _XPLATSTR("."); - const ::utility::string_t dotDotSegment = _XPLATSTR(".."); - /// /// Unreserved characters are those that are allowed in a URI but do not have a reserved purpose. They include: /// - A-Z @@ -445,6 +442,9 @@ namespace // 5.2.4. Remove Dot Segments https://tools.ietf.org/html/rfc3986#section-5.2.4 void removeDotSegments(uri_builder &builder) { + const ::utility::string_t dotSegment = _XPLATSTR("."); + const ::utility::string_t dotDotSegment = _XPLATSTR(".."); + if (builder.path().find(_XPLATSTR('.')) == utility::string_t::npos) return; From 8484f5d97af41a9b0980eed2bd5d736f4c355f1c Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Wed, 10 Oct 2018 18:12:37 -0700 Subject: [PATCH 273/438] Revert "Enable precompiled headers for test/functional (#891)" (#904) This reverts commit 2aa4a641b61c6d9d805c7a85b649671d4b55cd27 because it fails to compile: D:\cpprestsdk\build.debug>ninja ninja: error: dependency cycle: Release/tests/functional/http/client/stdafx.pch -> Release/tests/functional/http/client/CMakeFiles/httpclient_test.dir/stdafx.cpp.obj -> Release/tests/functional/http/client/stdafx.pch --- Release/tests/functional/http/client/CMakeLists.txt | 13 ------------- Release/tests/functional/json/CMakeLists.txt | 13 ------------- .../tests/functional/pplx/pplx_test/CMakeLists.txt | 13 ------------- Release/tests/functional/streams/CMakeLists.txt | 13 ------------- Release/tests/functional/uri/CMakeLists.txt | 13 ------------- Release/tests/functional/utils/CMakeLists.txt | 13 ------------- 6 files changed, 78 deletions(-) diff --git a/Release/tests/functional/http/client/CMakeLists.txt b/Release/tests/functional/http/client/CMakeLists.txt index 1cf9b6e6f5..17cf4eff81 100644 --- a/Release/tests/functional/http/client/CMakeLists.txt +++ b/Release/tests/functional/http/client/CMakeLists.txt @@ -32,19 +32,6 @@ else() target_link_libraries(httpclient_test PRIVATE httptest_utilities) endif() -if(MSVC) - get_target_property(_srcs httpclient_test SOURCES) - - if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") - set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") - set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") - endif() - - set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") - target_sources(httpclient_test PRIVATE stdafx.cpp) - target_compile_options(httpclient_test PRIVATE /Yustdafx.h /Zm200) -endif() - if(NOT WIN32) cpprest_find_boost() target_link_libraries(httpclient_test PRIVATE cpprestsdk_boost_internal) diff --git a/Release/tests/functional/json/CMakeLists.txt b/Release/tests/functional/json/CMakeLists.txt index c9dccfcfeb..379a6bd4bf 100644 --- a/Release/tests/functional/json/CMakeLists.txt +++ b/Release/tests/functional/json/CMakeLists.txt @@ -16,16 +16,3 @@ if(UNIX AND NOT APPLE) cpprest_find_boost() target_link_libraries(json_test PRIVATE cpprestsdk_boost_internal) endif() - -if(MSVC) - get_target_property(_srcs json_test SOURCES) - - if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") - set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") - set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") - endif() - - set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") - target_sources(json_test PRIVATE stdafx.cpp) - target_compile_options(json_test PRIVATE /Yustdafx.h /Zm200) -endif() diff --git a/Release/tests/functional/pplx/pplx_test/CMakeLists.txt b/Release/tests/functional/pplx/pplx_test/CMakeLists.txt index a51776989b..01c56f7522 100644 --- a/Release/tests/functional/pplx/pplx_test/CMakeLists.txt +++ b/Release/tests/functional/pplx/pplx_test/CMakeLists.txt @@ -6,16 +6,3 @@ set(SOURCES ) add_casablanca_test(pplx_test SOURCES) - -if(MSVC) - get_target_property(_srcs pplx_test SOURCES) - - if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") - set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") - set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") - endif() - - set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") - target_sources(pplx_test PRIVATE stdafx.cpp) - target_compile_options(pplx_test PRIVATE /Yustdafx.h /Zm200) -endif() diff --git a/Release/tests/functional/streams/CMakeLists.txt b/Release/tests/functional/streams/CMakeLists.txt index d2b6858f15..4b11173b18 100644 --- a/Release/tests/functional/streams/CMakeLists.txt +++ b/Release/tests/functional/streams/CMakeLists.txt @@ -24,16 +24,3 @@ if(NOT WIN32 OR CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") target_include_directories(streams_test PRIVATE $) endif() endif() - -if(MSVC) - get_target_property(_srcs streams_test SOURCES) - - if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") - set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") - set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") - endif() - - set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") - target_sources(streams_test PRIVATE stdafx.cpp) - target_compile_options(streams_test PRIVATE /Yustdafx.h /Zm200) -endif() diff --git a/Release/tests/functional/uri/CMakeLists.txt b/Release/tests/functional/uri/CMakeLists.txt index 1a4aaee947..54d80ac254 100644 --- a/Release/tests/functional/uri/CMakeLists.txt +++ b/Release/tests/functional/uri/CMakeLists.txt @@ -13,16 +13,3 @@ set(SOURCES ) add_casablanca_test(uri_test SOURCES) - -if(MSVC) - get_target_property(_srcs uri_test SOURCES) - - if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") - set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") - set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") - endif() - - set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") - target_sources(uri_test PRIVATE stdafx.cpp) - target_compile_options(uri_test PRIVATE /Yustdafx.h /Zm200) -endif() diff --git a/Release/tests/functional/utils/CMakeLists.txt b/Release/tests/functional/utils/CMakeLists.txt index ff5d4cb49c..ff175283f8 100644 --- a/Release/tests/functional/utils/CMakeLists.txt +++ b/Release/tests/functional/utils/CMakeLists.txt @@ -13,16 +13,3 @@ add_casablanca_test(utils_test SOURCES) if(CMAKE_COMPILER_IS_GNUCXX) target_compile_options(utils_test PRIVATE "-Wno-deprecated-declarations") endif() - -if(MSVC) - get_target_property(_srcs utils_test SOURCES) - - if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") - set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") - set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/stdafx.pch") - endif() - - set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") - target_sources(utils_test PRIVATE stdafx.cpp) - target_compile_options(utils_test PRIVATE /Yustdafx.h /Zm200) -endif() From acd96cfba2e12989bc69a152b8a320ac5ea50ee2 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Wed, 10 Oct 2018 20:11:20 -0700 Subject: [PATCH 274/438] Burninate internal use of ostringstream, and done a ref (#905) * Burninate internal use of ostringstream, and make compressors' done parameter required. * Remove errant ::details. * Remove even more errant ::details. --- Release/include/cpprest/http_compression.h | 4 +- Release/include/cpprest/json.h | 54 ++++---- Release/src/http/client/http_client_asio.cpp | 4 +- Release/src/http/client/http_client_msg.cpp | 41 ++++-- Release/src/http/client/http_client_winrt.cpp | 3 +- Release/src/http/common/http_compression.cpp | 95 +++++-------- Release/src/http/common/http_msg.cpp | 18 +-- .../src/http/listener/http_server_asio.cpp | 9 +- .../src/http/listener/http_server_httpsys.cpp | 18 ++- Release/src/http/oauth/oauth1.cpp | 123 ++++++++++------- Release/src/http/oauth/oauth2.cpp | 11 +- Release/src/json/json_parsing.cpp | 11 +- Release/src/utilities/asyncrt_utils.cpp | 128 ++++++++++-------- .../src/websockets/client/ws_client_wspp.cpp | 12 +- Release/src/websockets/client/ws_msg.cpp | 2 +- .../http/client/compression_tests.cpp | 43 +++--- 16 files changed, 305 insertions(+), 271 deletions(-) diff --git a/Release/include/cpprest/http_compression.h b/Release/include/cpprest/http_compression.h index 1993e6244c..b6df43e026 100644 --- a/Release/include/cpprest/http_compression.h +++ b/Release/include/cpprest/http_compression.h @@ -51,7 +51,7 @@ class compress_provider size_t output_size, operation_hint hint, size_t& input_bytes_processed, - bool* done = nullptr) = 0; + bool& done) = 0; virtual pplx::task compress( const uint8_t* input, size_t input_size, uint8_t* output, size_t output_size, operation_hint hint) = 0; virtual void reset() = 0; @@ -71,7 +71,7 @@ class decompress_provider size_t output_size, operation_hint hint, size_t& input_bytes_processed, - bool* done = nullptr) = 0; + bool& done) = 0; virtual pplx::task decompress( const uint8_t* input, size_t input_size, uint8_t* output, size_t output_size, operation_hint hint) = 0; virtual void reset() = 0; diff --git a/Release/include/cpprest/json.h b/Release/include/cpprest/json.h index dfdeead4f3..1e88ddd2f0 100644 --- a/Release/include/cpprest/json.h +++ b/Release/include/cpprest/json.h @@ -714,7 +714,11 @@ namespace json private: std::string _message; public: - json_exception(const utility::char_t * const &message) : _message(utility::conversions::to_utf8string(message)) { } + json_exception(const char * const message) : _message(message) { } +#ifdef _UTF16_STRINGS + json_exception(const wchar_t * const message) : _message(utility::conversions::utf16_to_utf8(message)) { } +#endif // _UTF16_STRINGS + json_exception(std::string&& message) : _message(std::move(message)) { } // Must be narrow string because it derives from std::exception const char* what() const CPPREST_NOEXCEPT @@ -930,7 +934,7 @@ namespace json { if (index >= m_elements.size()) { - throw json_exception(_XPLATSTR("index out of bounds")); + throw json_exception("index out of bounds"); } m_elements.erase(m_elements.begin() + index); } @@ -943,7 +947,7 @@ namespace json json::value& at(size_type index) { if (index >= m_elements.size()) - throw json_exception(_XPLATSTR("index out of bounds")); + throw json_exception("index out of bounds"); return m_elements[index]; } @@ -956,7 +960,7 @@ namespace json const json::value& at(size_type index) const { if (index >= m_elements.size()) - throw json_exception(_XPLATSTR("index out of bounds")); + throw json_exception("index out of bounds"); return m_elements[index]; } @@ -1145,7 +1149,7 @@ namespace json auto iter = find_by_key(key); if (iter == m_elements.end()) { - throw web::json::json_exception(_XPLATSTR("Key not found")); + throw web::json::json_exception("Key not found"); } m_elements.erase(iter); @@ -1161,7 +1165,7 @@ namespace json auto iter = find_by_key(key); if (iter == m_elements.end()) { - throw web::json::json_exception(_XPLATSTR("Key not found")); + throw web::json::json_exception("Key not found"); } return iter->second; @@ -1177,7 +1181,7 @@ namespace json auto iter = find_by_key(key); if (iter == m_elements.end()) { - throw web::json::json_exception(_XPLATSTR("Key not found")); + throw web::json::json_exception("Key not found"); } return iter->second; @@ -1464,14 +1468,14 @@ namespace json virtual std::unique_ptr<_Value> _copy_value() = 0; virtual bool has_field(const utility::string_t &) const { return false; } - virtual value get_field(const utility::string_t &) const { throw json_exception(_XPLATSTR("not an object")); } - virtual value get_element(array::size_type) const { throw json_exception(_XPLATSTR("not an array")); } + virtual value get_field(const utility::string_t &) const { throw json_exception("not an object"); } + virtual value get_element(array::size_type) const { throw json_exception("not an array"); } - virtual value &index(const utility::string_t &) { throw json_exception(_XPLATSTR("not an object")); } - virtual value &index(array::size_type) { throw json_exception(_XPLATSTR("not an array")); } + virtual value &index(const utility::string_t &) { throw json_exception("not an object"); } + virtual value &index(array::size_type) { throw json_exception("not an array"); } - virtual const value &cnst_index(const utility::string_t &) const { throw json_exception(_XPLATSTR("not an object")); } - virtual const value &cnst_index(array::size_type) const { throw json_exception(_XPLATSTR("not an array")); } + virtual const value &cnst_index(const utility::string_t &) const { throw json_exception("not an object"); } + virtual const value &cnst_index(array::size_type) const { throw json_exception("not an array"); } // Common function used for serialization to strings and streams. virtual void serialize_impl(std::string& str) const @@ -1494,18 +1498,18 @@ namespace json virtual json::value::value_type type() const { return json::value::Null; } - virtual bool is_integer() const { throw json_exception(_XPLATSTR("not a number")); } - virtual bool is_double() const { throw json_exception(_XPLATSTR("not a number")); } - - virtual const json::number& as_number() { throw json_exception(_XPLATSTR("not a number")); } - virtual double as_double() const { throw json_exception(_XPLATSTR("not a number")); } - virtual int as_integer() const { throw json_exception(_XPLATSTR("not a number")); } - virtual bool as_bool() const { throw json_exception(_XPLATSTR("not a boolean")); } - virtual json::array& as_array() { throw json_exception(_XPLATSTR("not an array")); } - virtual const json::array& as_array() const { throw json_exception(_XPLATSTR("not an array")); } - virtual json::object& as_object() { throw json_exception(_XPLATSTR("not an object")); } - virtual const json::object& as_object() const { throw json_exception(_XPLATSTR("not an object")); } - virtual const utility::string_t& as_string() const { throw json_exception(_XPLATSTR("not a string")); } + virtual bool is_integer() const { throw json_exception("not a number"); } + virtual bool is_double() const { throw json_exception("not a number"); } + + virtual const json::number& as_number() { throw json_exception("not a number"); } + virtual double as_double() const { throw json_exception("not a number"); } + virtual int as_integer() const { throw json_exception("not a number"); } + virtual bool as_bool() const { throw json_exception("not a boolean"); } + virtual json::array& as_array() { throw json_exception("not an array"); } + virtual const json::array& as_array() const { throw json_exception("not an array"); } + virtual json::object& as_object() { throw json_exception("not an object"); } + virtual const json::object& as_object() const { throw json_exception("not an object"); } + virtual const utility::string_t& as_string() const { throw json_exception("not a string"); } virtual size_t size() const { return 0; } diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 72e13f046c..7ee22133fe 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -1530,7 +1530,7 @@ class asio_context final : public request_context, public std::enable_shared_fro size_t got; size_t inbytes = 0; size_t outbytes = 0; - bool done = false; + bool done; try { @@ -1547,7 +1547,7 @@ class asio_context final : public request_context, public std::enable_shared_fro output.size() - outbytes, web::http::compression::operation_hint::has_more, processed, - &done); + done); inbytes += processed; outbytes += got; } while (got && !done); diff --git a/Release/src/http/client/http_client_msg.cpp b/Release/src/http/client/http_client_msg.cpp index 9cab7c8da9..dd7f3dc5c5 100644 --- a/Release/src/http/client/http_client_msg.cpp +++ b/Release/src/http/client/http_client_msg.cpp @@ -12,6 +12,7 @@ ****/ #include "stdafx.h" #include "../common/internal_http_helpers.h" +#include "cpprest/asyncrt_utils.h" namespace web { namespace http { @@ -61,29 +62,41 @@ void details::_http_request::set_request_uri(const uri& relative) utility::string_t details::_http_request::to_string() const { - utility::ostringstream_t buffer; - buffer.imbue(std::locale::classic()); - buffer << m_method << _XPLATSTR(" ") << (this->m_uri.is_empty() ? _XPLATSTR("/") : this->m_uri.to_string()) << _XPLATSTR(" HTTP/1.1\r\n"); - buffer << http_msg_base::to_string(); - return buffer.str(); + utility::string_t result(m_method); + result += _XPLATSTR(' '); + if (this->m_uri.is_empty()) + { + result += _XPLATSTR('/'); + } + else + { + result += this->m_uri.to_string(); + } + + result += _XPLATSTR(" HTTP/1.1\r\n"); + result += http_msg_base::to_string(); + return result; } utility::string_t details::_http_response::to_string() const { + utility::string_t result(_XPLATSTR("HTTP/1.1 ")); + result += utility::conversions::details::to_string_t(m_status_code); + result += ' '; // If the user didn't explicitly set a reason phrase then we should have it default // if they used one of the standard known status codes. - auto reason_phrase = m_reason_phrase; - if(reason_phrase.empty()) + if (m_reason_phrase.empty()) { - reason_phrase = get_default_reason_phrase(status_code()); + result += get_default_reason_phrase(status_code()); + } + else + { + result += m_reason_phrase; } - utility::ostringstream_t buffer; - buffer.imbue(std::locale::classic()); - buffer << _XPLATSTR("HTTP/1.1 ") << m_status_code << _XPLATSTR(" ") << reason_phrase << _XPLATSTR("\r\n"); - - buffer << http_msg_base::to_string(); - return buffer.str(); + result += _XPLATSTR("\r\n"); + result += http_msg_base::to_string(); + return result; } }} // namespace web::http diff --git a/Release/src/http/client/http_client_winrt.cpp b/Release/src/http/client/http_client_winrt.cpp index 5a0697b489..79f682ec50 100644 --- a/Release/src/http/client/http_client_winrt.cpp +++ b/Release/src/http/client/http_client_winrt.cpp @@ -160,7 +160,8 @@ class HttpRequestCallback final : std::wstring msg(L"IXMLHttpRequest2Callback::OnError: "); msg.append(std::to_wstring(hrError)); msg.append(L": "); - msg.append(utility::conversions::to_string_t(utility::details::windows_category().message(hrError))); + msg.append(utility::conversions::to_string_t( + utility::details::windows_category().message(hrError))); m_request->report_error(hrError, msg); } else diff --git a/Release/src/http/common/http_compression.cpp b/Release/src/http/common/http_compression.cpp index 194f1efc97..9d409906c5 100644 --- a/Release/src/http/common/http_compression.cpp +++ b/Release/src/http/common/http_compression.cpp @@ -75,23 +75,19 @@ class zlib_compressor_base : public compress_provider size_t output_size, operation_hint hint, size_t& input_bytes_processed, - bool* done) + bool& done) { if (m_state == Z_STREAM_END || (hint != operation_hint::is_last && !input_size)) { input_bytes_processed = 0; - if (done) - { - *done = (m_state == Z_STREAM_END); - } + done = (m_state == Z_STREAM_END); return 0; } if (m_state != Z_OK && m_state != Z_BUF_ERROR && m_state != Z_STREAM_ERROR) { - std::stringstream ss; - ss << "Prior unrecoverable compression stream error " << m_state; - throw std::runtime_error(std::move(ss.str())); + throw std::runtime_error("Prior unrecoverable compression stream error " + + std::to_string(m_state)); } if (input_size > std::numeric_limits::max() || output_size > std::numeric_limits::max()) @@ -108,16 +104,11 @@ class zlib_compressor_base : public compress_provider if (m_state != Z_OK && m_state != Z_STREAM_ERROR && !(hint == operation_hint::is_last && (m_state == Z_STREAM_END || m_state == Z_BUF_ERROR))) { - std::stringstream ss; - ss << "Unrecoverable compression stream error " << m_state; - throw std::runtime_error(std::move(ss.str())); + throw std::runtime_error("Unrecoverable compression stream error " + std::to_string(m_state)); } input_bytes_processed = input_size - m_stream.avail_in; - if (done) - { - *done = (m_state == Z_STREAM_END); - } + done = (m_state == Z_STREAM_END); return output_size - m_stream.avail_out; } @@ -129,7 +120,7 @@ class zlib_compressor_base : public compress_provider try { r.output_bytes_produced = - compress(input, input_size, output, output_size, hint, r.input_bytes_processed, &r.done); + compress(input, input_size, output, output_size, hint, r.input_bytes_processed, r.done); } catch (...) { @@ -146,9 +137,7 @@ class zlib_compressor_base : public compress_provider m_state = deflateReset(&m_stream); if (m_state != Z_OK) { - std::stringstream ss; - ss << "Failed to reset zlib compressor " << m_state; - throw std::runtime_error(std::move(ss.str())); + throw std::runtime_error("Failed to reset zlib compressor " + std::to_string(m_state)); } } @@ -181,23 +170,18 @@ class zlib_decompressor_base : public decompress_provider size_t output_size, operation_hint hint, size_t& input_bytes_processed, - bool* done) + bool& done) { if (m_state == Z_STREAM_END || !input_size) { input_bytes_processed = 0; - if (done) - { - *done = (m_state == Z_STREAM_END); - } + done = (m_state == Z_STREAM_END); return 0; } if (m_state != Z_OK && m_state != Z_BUF_ERROR && m_state != Z_STREAM_ERROR) { - std::stringstream ss; - ss << "Prior unrecoverable decompression stream error " << m_state; - throw std::runtime_error(std::move(ss.str())); + throw std::runtime_error("Prior unrecoverable decompression stream error " + std::to_string(m_state)); } if (input_size > std::numeric_limits::max() || output_size > std::numeric_limits::max()) @@ -215,16 +199,11 @@ class zlib_decompressor_base : public decompress_provider { // Z_BUF_ERROR is a success code for Z_FINISH, and the caller can continue as if operation_hint::is_last was // not given - std::stringstream ss; - ss << "Unrecoverable decompression stream error " << m_state; - throw std::runtime_error(std::move(ss.str())); + throw std::runtime_error("Unrecoverable decompression stream error " + std::to_string(m_state)); } input_bytes_processed = input_size - m_stream.avail_in; - if (done) - { - *done = (m_state == Z_STREAM_END); - } + done = (m_state == Z_STREAM_END); return output_size - m_stream.avail_out; } @@ -236,7 +215,7 @@ class zlib_decompressor_base : public decompress_provider try { r.output_bytes_produced = - decompress(input, input_size, output, output_size, hint, r.input_bytes_processed, &r.done); + decompress(input, input_size, output, output_size, hint, r.input_bytes_processed, r.done); } catch (...) { @@ -253,9 +232,7 @@ class zlib_decompressor_base : public decompress_provider m_state = inflateReset(&m_stream); if (m_state != Z_OK) { - std::stringstream ss; - ss << "Failed to reset zlib decompressor " << m_state; - throw std::runtime_error(std::move(ss.str())); + throw std::runtime_error("Failed to reset zlib decompressor " + std::to_string(m_state)); } } @@ -331,15 +308,12 @@ class brotli_compressor : public compress_provider size_t output_size, operation_hint hint, size_t& input_bytes_processed, - bool* done) + bool& done) { if (m_done || (hint != operation_hint::is_last && !input_size)) { input_bytes_processed = 0; - if (done) - { - *done = m_done; - } + done = m_done; return 0; } @@ -397,10 +371,7 @@ class brotli_compressor : public compress_provider } input_bytes_processed = input_size - avail_in; - if (done) - { - *done = m_done; - } + done = m_done; return output_size - avail_out; } @@ -495,15 +466,12 @@ class brotli_decompressor : public decompress_provider size_t output_size, operation_hint hint, size_t& input_bytes_processed, - bool* done) + bool& done) { if (m_state == BROTLI_DECODER_RESULT_SUCCESS /* || !input_size*/) { input_bytes_processed = 0; - if (done) - { - *done = (m_state == BROTLI_DECODER_RESULT_SUCCESS); - } + done = (m_state == BROTLI_DECODER_RESULT_SUCCESS); return 0; } @@ -529,10 +497,7 @@ class brotli_decompressor : public decompress_provider } input_bytes_processed = input_size - avail_in; - if (done) - { - *done = (m_state == BROTLI_DECODER_RESULT_SUCCESS); - } + done = (m_state == BROTLI_DECODER_RESULT_SUCCESS); return output_size - avail_out; } @@ -761,7 +726,7 @@ std::unique_ptr make_gzip_compressor(int compressionLevel, in return std::unique_ptr(); #endif // CPPREST_HTTP_COMPRESSION } - + std::unique_ptr make_deflate_compressor(int compressionLevel, int method, int strategy, int memLevel) { #if defined(CPPREST_HTTP_COMPRESSION) @@ -1088,14 +1053,13 @@ utility::string_t build_supported_header(header_types type, { const std::vector>& f = factories.empty() ? web::http::compression::builtin::g_decompress_factories : factories; - utility::ostringstream_t os; + utility::string_t result; bool start; _ASSERTE(type == header_types::te || type == header_types::accept_encoding); // Add all specified algorithms and their weights to the header start = true; - os.imbue(std::locale::classic()); for (auto& factory : f) { if (factory) @@ -1104,12 +1068,15 @@ utility::string_t build_supported_header(header_types type, if (!start) { - os << _XPLATSTR(", "); + result += _XPLATSTR(", "); } - os << factory->algorithm(); + result += factory->algorithm(); if (weight <= 1000) { - os << _XPLATSTR(";q=") << weight / 1000 << _XPLATSTR(".") << weight % 1000; + result += _XPLATSTR(";q="); + result += utility::conversions::details::to_string_t(weight / 1000); + result += _XPLATSTR('.'); + result += utility::conversions::details::to_string_t(weight % 1000); } start = false; } @@ -1118,10 +1085,10 @@ utility::string_t build_supported_header(header_types type, if (start && type == header_types::accept_encoding) { // Request that no encoding be applied - os << _XPLATSTR("identity;q=1, *;q=0"); + result += _XPLATSTR("identity;q=1, *;q=0"); } - return os.str(); + return result; } } // namespace details } // namespace compression diff --git a/Release/src/http/common/http_msg.cpp b/Release/src/http/common/http_msg.cpp index 7a80017828..44870f5420 100644 --- a/Release/src/http/common/http_msg.cpp +++ b/Release/src/http/common/http_msg.cpp @@ -253,7 +253,7 @@ void parse_headers_string(_Inout_z_ utf16char *headersStr, http_headers &headers http_version __cdecl http_version::from_string(const std::string& http_version_string) { - std::stringstream str(http_version_string); + std::istringstream str(http_version_string); str.imbue(std::locale::classic()); std::string http; std::getline(str, http, '/'); @@ -1009,22 +1009,24 @@ static utility::string_t convert_body_to_string_t(const utility::string_t &conte // static utility::string_t http_headers_body_to_string(const http_headers &headers, concurrency::streams::istream instream) { - utility::ostringstream_t buffer; - buffer.imbue(std::locale::classic()); - + utility::string_t result; for (const auto &header : headers) { - buffer << header.first << _XPLATSTR(": ") << header.second << CRLF; + result += header.first; + result += _XPLATSTR(": "); + result += header.second; + result += CRLF; } - buffer << CRLF; + + result += CRLF; utility::string_t content_type; if(headers.match(http::header_names::content_type, content_type)) { - buffer << convert_body_to_string_t(content_type, instream); + result += convert_body_to_string_t(content_type, instream); } - return buffer.str(); + return result; } utility::string_t details::http_msg_base::to_string() const diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 13b813b858..5ab3086954 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -693,7 +693,8 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys // Get the path - remove the version portion and prefix space try { - m_request.set_request_uri(utility::conversions::to_string_t(http_path_and_version.substr(1, http_path_and_version.size() - VersionPortionSize - 1))); + m_request.set_request_uri(utility::conversions::to_string_t( + http_path_and_version.substr(1, http_path_and_version.size() - VersionPortionSize - 1))); } catch (const std::exception& e) // may be std::range_error indicating invalid Unicode, or web::uri_exception { @@ -722,7 +723,8 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys auto endpoint = m_socket->remote_endpoint(socket_ec); if (!socket_ec) { - m_request._get_impl()->_set_remote_address(utility::conversions::to_string_t(endpoint.address().to_string())); + m_request._get_impl()->_set_remote_address(utility::conversions::to_string_t( + endpoint.address().to_string())); } return handle_headers(); @@ -743,7 +745,8 @@ will_deref_and_erase_t asio_server_connection::handle_headers() if (colon != std::string::npos && colon != 0) { auto name = utility::conversions::to_string_t(header.substr(0, colon)); - auto value = utility::conversions::to_string_t(header.substr(colon + 1, header.length() - (colon + 1))); // also exclude '\r' + auto value = utility::conversions::to_string_t( + header.substr(colon + 1, header.length() - (colon + 1))); // also exclude '\r' web::http::details::trim_whitespace(name); web::http::details::trim_whitespace(value); diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp index 3adb4fb882..242dae4800 100644 --- a/Release/src/http/listener/http_server_httpsys.cpp +++ b/Release/src/http/listener/http_server_httpsys.cpp @@ -243,7 +243,7 @@ pplx::task http_windows_server::register_listener(_In_ web::http::experime utility::string_t host_uri = http::uri::decode(u.to_string()); if(host_uri.back() != U('/') && u.query().empty() && u.fragment().empty()) { - host_uri.append(U("/")); + host_uri.push_back(U('/')); } // inside here we check for a few specific error types that know about @@ -252,19 +252,16 @@ pplx::task http_windows_server::register_listener(_In_ web::http::experime if(errorCode) { HttpCloseUrlGroup(urlGroupId); - utility::stringstream_t os; - os.imbue(std::locale::classic()); - if(errorCode == ERROR_ALREADY_EXISTS || errorCode == ERROR_SHARING_VIOLATION) { - os << _XPLATSTR("Address '") << pListener->uri().to_string() << _XPLATSTR("' is already in use"); - return pplx::task_from_exception(http_exception(errorCode, os.str())); + return pplx::task_from_exception(http_exception(errorCode, + _XPLATSTR("Address '") + pListener->uri().to_string() + _XPLATSTR("' is already in use"))); } else if (errorCode == ERROR_ACCESS_DENIED) { - os << _XPLATSTR("Access denied: attempting to add Address '") << pListener->uri().to_string() << _XPLATSTR("'. "); - os << _XPLATSTR("Run as administrator to listen on an hostname other than localhost, or to listen on port 80."); - return pplx::task_from_exception(http_exception(errorCode, os.str())); + return pplx::task_from_exception(http_exception(errorCode, + _XPLATSTR("Access denied: attempting to add Address '") + pListener->uri().to_string() + _XPLATSTR("'. ") + _XPLATSTR("Run as administrator to listen on an hostname other than localhost, or to listen on port 80."))); } else { @@ -738,7 +735,8 @@ void windows_request_context::read_body_io_completion(DWORD error_code, DWORD by auto body = request_body_buf.alloc(CHUNK_SIZE); try { - got = m_decompressor->decompress(m_compress_buffer.data()+total_used, bytes_read-total_used, body, CHUNK_SIZE, http::compression::operation_hint::has_more, used, NULL); + bool done_unused; + got = m_decompressor->decompress(m_compress_buffer.data()+total_used, bytes_read-total_used, body, CHUNK_SIZE, http::compression::operation_hint::has_more, used, done_unused); } catch (...) { diff --git a/Release/src/http/oauth/oauth1.cpp b/Release/src/http/oauth/oauth1.cpp index 37c71deb22..22029593b8 100644 --- a/Release/src/http/oauth/oauth1.cpp +++ b/Release/src/http/oauth/oauth1.cpp @@ -12,6 +12,7 @@ ****/ #include "stdafx.h" +#include "cpprest/asyncrt_utils.h" #if !defined(CPPREST_TARGET_XP) @@ -153,15 +154,17 @@ std::vector oauth1_config::_hmac_sha1(const utility::string_t& ke // - If URI port is unspecified. utility::string_t oauth1_config::_build_base_string_uri(const uri& u) { - utility::ostringstream_t os; - os.imbue(std::locale::classic()); - os << u.scheme() << "://" << u.host(); + utility::string_t result(u.scheme()); + result += _XPLATSTR("://"); + result += u.host(); if (!u.is_port_default() && u.port() != 80 && u.port() != 443) { - os << ":" << u.port(); + result += _XPLATSTR(':'); + result += utility::conversions::details::to_string_t(u.port()); } - os << u.path(); - return uri::encode_data_string(os.str()); + + result += u.path(); + return uri::encode_data_string(std::move(result)); } utility::string_t oauth1_config::_build_normalized_parameters(web::http::uri u, const oauth1_state& state) const @@ -172,18 +175,12 @@ utility::string_t oauth1_config::_build_normalized_parameters(web::http::uri u, std::vector queries; for (const auto& query : queries_map) { - utility::ostringstream_t os; - os.imbue(std::locale::classic()); - os << query.first << "=" << query.second; - queries.push_back(os.str()); + queries.push_back(query.first + _XPLATSTR('=') + query.second); } for (const auto& query : parameters()) { - utility::ostringstream_t os; - os.imbue(std::locale::classic()); - os << query.first << "=" << query.second; - queries.push_back(os.str()); + queries.push_back(query.first + _XPLATSTR('=') + query.second); } // Push oauth1 parameters. @@ -202,15 +199,21 @@ utility::string_t oauth1_config::_build_normalized_parameters(web::http::uri u, } // Sort parameters and build the string. - sort(queries.begin(), queries.end()); - utility::ostringstream_t os; - os.imbue(std::locale::classic()); - for (auto i = queries.begin(); i != queries.end() - 1; ++i) + utility::string_t result; + if (!queries.empty()) { - os << *i << U("&"); + auto i = queries.begin(); + auto e = queries.end(); + sort(i, e); + result = *i; + while (++i != e) + { + result += _XPLATSTR('&'); + result += *i; + } } - os << queries.back(); - return uri::encode_data_string(os.str()); + + return uri::encode_data_string(result); } static bool is_application_x_www_form_urlencoded (http_request &request) @@ -222,10 +225,9 @@ static bool is_application_x_www_form_urlencoded (http_request &request) utility::string_t oauth1_config::_build_signature_base_string(http_request request, oauth1_state state) const { uri u(request.absolute_uri()); - utility::ostringstream_t os; - os.imbue(std::locale::classic()); - os << request.method(); - os << "&" << _build_base_string_uri(u); + utility::string_t result(request.method()); + result += _XPLATSTR('&'); + result += _build_base_string_uri(u); // http://oauth.net/core/1.0a/#signing_process // 9.1.1. Normalize Request Parameters @@ -233,19 +235,21 @@ utility::string_t oauth1_config::_build_signature_base_string(http_request reque // - Parameters in the OAuth HTTP Authorization header excluding the realm parameter. // - Parameters in the HTTP POST request body (with a content-type of application/x-www-form-urlencoded). // - HTTP GET parameters added to the URLs in the query part (as defined by [RFC3986] section 3). + result += _XPLATSTR('&'); if (is_application_x_www_form_urlencoded(request)) { // Note: this should be improved to not block and handle any potential exceptions. utility::string_t str = request.extract_string(true).get(); request.set_body(str, web::http::details::mime_types::application_x_www_form_urlencoded); uri v = http::uri_builder(request.absolute_uri()).append_query(std::move(str), false).to_uri(); - os << "&" << _build_normalized_parameters(std::move(v), std::move(state)); + result += _build_normalized_parameters(std::move(v), std::move(state)); } else { - os << "&" << _build_normalized_parameters(std::move(u), std::move(state)); + result += _build_normalized_parameters(std::move(u), std::move(state)); } - return os.str(); + + return result; } utility::string_t oauth1_config::_build_signature(http_request request, oauth1_state state) const @@ -323,31 +327,57 @@ pplx::task oauth1_config::_request_token(oauth1_state state, bool is_temp_ void oauth1_config::_authenticate_request(http_request &request, oauth1_state state) { - utility::ostringstream_t os; - os.imbue(std::locale::classic()); - os << "OAuth "; + utility::string_t authHeader(_XPLATSTR("OAuth ")); if (!realm().empty()) { - os << oauth1_strings::realm << "=\"" << web::uri::encode_data_string (realm()) << "\", "; + authHeader += oauth1_strings::realm; + authHeader += _XPLATSTR("=\""); + authHeader += web::uri::encode_data_string(realm()); + authHeader += _XPLATSTR("\", "); } - os << oauth1_strings::version << "=\"1.0"; - os << "\", " << oauth1_strings::consumer_key << "=\"" << web::uri::encode_data_string (consumer_key()); + + authHeader += oauth1_strings::version; + authHeader += _XPLATSTR("=\"1.0\", "); + authHeader += oauth1_strings::consumer_key; + authHeader += _XPLATSTR("=\""); + authHeader += web::uri::encode_data_string (consumer_key()); + if (!m_token.access_token().empty()) { - os << "\", " << oauth1_strings::token << "=\"" << web::uri::encode_data_string(m_token.access_token()); + authHeader += _XPLATSTR("\", "); + authHeader += oauth1_strings::token; + authHeader += _XPLATSTR("=\""); + authHeader += web::uri::encode_data_string(m_token.access_token()); } - os << "\", " << oauth1_strings::signature_method << "=\"" << method(); - os << "\", " << oauth1_strings::timestamp << "=\"" << state.timestamp(); - os << "\", " << oauth1_strings::nonce << "=\"" << state.nonce(); - os << "\", " << oauth1_strings::signature << "=\"" << uri::encode_data_string(_build_signature(request, state)); - os << "\""; + + authHeader += _XPLATSTR("\", "); + authHeader += oauth1_strings::signature_method; + authHeader += _XPLATSTR("=\""); + authHeader += method(); + authHeader += _XPLATSTR("\", "); + authHeader += oauth1_strings::timestamp; + authHeader += _XPLATSTR("=\""); + authHeader += state.timestamp(); + authHeader += _XPLATSTR("\", "); + authHeader += oauth1_strings::nonce; + authHeader += _XPLATSTR("=\""); + authHeader += state.nonce(); + authHeader += _XPLATSTR("\", "); + authHeader += oauth1_strings::signature; + authHeader += _XPLATSTR("=\""); + authHeader += uri::encode_data_string(_build_signature(request, state)); + authHeader += _XPLATSTR("\""); if (!state.extra_key().empty()) { - os << ", " << state.extra_key() << "=\"" << web::uri::encode_data_string(state.extra_value()) << "\""; + authHeader += _XPLATSTR(", "); + authHeader += state.extra_key(); + authHeader += _XPLATSTR("=\""); + authHeader += web::uri::encode_data_string(state.extra_value()); + authHeader += _XPLATSTR("\""); } - request.headers().add(header_names::authorization, os.str()); + request.headers().add(header_names::authorization, std::move(authHeader)); } pplx::task oauth1_config::build_authorization_uri() @@ -373,11 +403,10 @@ pplx::task oauth1_config::token_from_redirected_uri(const web::http::uri& } if (m_token.access_token() != token_param->second) { - utility::ostringstream_t err; - err.imbue(std::locale::classic()); - err << U("redirected URI parameter 'oauth_token'='") << token_param->second - << U("' does not match temporary token='") << m_token.access_token() << U("'."); - return pplx::task_from_exception(oauth1_exception(err.str().c_str())); + return pplx::task_from_exception(oauth1_exception( + _XPLATSTR("redirected URI parameter 'oauth_token'='") + token_param->second + + _XPLATSTR("' does not match temporary token='") + m_token.access_token() + _XPLATSTR("'.") + )); } auto verifier_param = query.find(oauth1_strings::verifier); diff --git a/Release/src/http/oauth/oauth2.cpp b/Release/src/http/oauth/oauth2.cpp index 247241933f..c85cf44c2f 100644 --- a/Release/src/http/oauth/oauth2.cpp +++ b/Release/src/http/oauth/oauth2.cpp @@ -71,11 +71,12 @@ pplx::task oauth2_config::token_from_redirected_uri(const web::http::uri& } if (state() != state_param->second) { - utility::ostringstream_t err; - err.imbue(std::locale::classic()); - err << U("redirected URI parameter 'state'='") << state_param->second - << U("' does not match state='") << state() << U("'."); - return pplx::task_from_exception(oauth2_exception(err.str())); + utility::string_t err(_XPLATSTR("redirected URI parameter 'state'='")); + err += state_param->second; + err += _XPLATSTR("' does not match state='"); + err += state(); + err += _XPLATSTR("'."); + return pplx::task_from_exception(oauth2_exception(std::move(err))); } auto code_param = query.find(oauth2_strings::code); diff --git a/Release/src/json/json_parsing.cpp b/Release/src/json/json_parsing.cpp index 295bd6e16a..a73a84b3ad 100644 --- a/Release/src/json/json_parsing.cpp +++ b/Release/src/json/json_parsing.cpp @@ -49,10 +49,13 @@ template #endif void CreateException(const Token &tk, const utility::string_t &message) { - utility::ostringstream_t os; - os << _XPLATSTR("* Line ") << tk.start.m_line << _XPLATSTR(", Column ") << tk.start.m_column << _XPLATSTR(" Syntax error: ") << message; - utility::string_t osStr = os.str(); - throw web::json::json_exception(osStr.c_str()); + std::string str("* Line "); + str += std::to_string(tk.start.m_line); + str += ", Column "; + str += std::to_string(tk.start.m_column); + str += " Syntax error: "; + str += utility::conversions::to_utf8string(message); + throw web::json::json_exception(std::move(str)); } template diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index e971c3c544..3903ce9ca7 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -275,11 +275,10 @@ std::string windows_category_impl::message(int errorCode) const CPPREST_NOEXCEPT &buffer[0], buffer_size, NULL); + if (result == 0) { - std::ostringstream os; - os << "Unable to get an error message for error code: " << errorCode << "."; - return os.str(); + return "Unable to get an error message for error code: " + std::to_string(errorCode) + "."; } return utility::conversions::to_utf8string(buffer); @@ -688,80 +687,92 @@ utility::string_t datetime::to_string(date_format format) const throw utility::details::create_system_error(GetLastError()); } - std::wostringstream outStream; - outStream.imbue(std::locale::classic()); - + std::wstring result; if (format == RFC_1123) { + { + wchar_t dateStr[18] = {0}; #if _WIN32_WINNT < _WIN32_WINNT_VISTA - TCHAR dateStr[18] = {0}; - status = GetDateFormat(LOCALE_INVARIANT, 0, &systemTime, __TEXT("ddd',' dd MMM yyyy"), dateStr, sizeof(dateStr) / sizeof(TCHAR)); + status = GetDateFormatW(LOCALE_INVARIANT, 0, &systemTime, L"ddd',' dd MMM yyyy", dateStr, sizeof(dateStr) / sizeof(wchar_t)); #else - wchar_t dateStr[18] = {0}; - status = GetDateFormatEx(LOCALE_NAME_INVARIANT, 0, &systemTime, L"ddd',' dd MMM yyyy", dateStr, sizeof(dateStr) / sizeof(wchar_t), NULL); + status = GetDateFormatEx(LOCALE_NAME_INVARIANT, 0, &systemTime, L"ddd',' dd MMM yyyy", dateStr, sizeof(dateStr) / sizeof(wchar_t), NULL); #endif // _WIN32_WINNT < _WIN32_WINNT_VISTA - if (status == 0) - { - throw utility::details::create_system_error(GetLastError()); + if (status == 0) + { + throw utility::details::create_system_error(GetLastError()); + } + + result += dateStr; + result += L' '; } + { + wchar_t timeStr[10] = {0}; #if _WIN32_WINNT < _WIN32_WINNT_VISTA - TCHAR timeStr[10] = {0}; - status = GetTimeFormat(LOCALE_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, __TEXT("HH':'mm':'ss"), timeStr, sizeof(timeStr) / sizeof(TCHAR)); + status = GetTimeFormatW(LOCALE_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L"HH':'mm':'ss", timeStr, sizeof(timeStr) / sizeof(wchar_t)); #else - wchar_t timeStr[10] = {0}; - status = GetTimeFormatEx(LOCALE_NAME_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L"HH':'mm':'ss", timeStr, sizeof(timeStr) / sizeof(wchar_t)); + status = GetTimeFormatEx(LOCALE_NAME_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L"HH':'mm':'ss", timeStr, sizeof(timeStr) / sizeof(wchar_t)); #endif // _WIN32_WINNT < _WIN32_WINNT_VISTA - if (status == 0) - { - throw utility::details::create_system_error(GetLastError()); + if (status == 0) + { + throw utility::details::create_system_error(GetLastError()); + } + + result += timeStr; + result += L" GMT"; } - outStream << dateStr << " " << timeStr << " " << "GMT"; } else if (format == ISO_8601) { const size_t buffSize = 64; + { + wchar_t dateStr[buffSize] = {0}; #if _WIN32_WINNT < _WIN32_WINNT_VISTA - TCHAR dateStr[buffSize] = {0}; - status = GetDateFormat(LOCALE_INVARIANT, 0, &systemTime, __TEXT("yyyy-MM-dd"), dateStr, buffSize); + status = GetDateFormatW(LOCALE_INVARIANT, 0, &systemTime, L"yyyy-MM-dd", dateStr, buffSize); #else - wchar_t dateStr[buffSize] = {0}; - status = GetDateFormatEx(LOCALE_NAME_INVARIANT, 0, &systemTime, L"yyyy-MM-dd", dateStr, buffSize, NULL); + status = GetDateFormatEx(LOCALE_NAME_INVARIANT, 0, &systemTime, L"yyyy-MM-dd", dateStr, buffSize, NULL); #endif // _WIN32_WINNT < _WIN32_WINNT_VISTA - if (status == 0) - { - throw utility::details::create_system_error(GetLastError()); + if (status == 0) + { + throw utility::details::create_system_error(GetLastError()); + } + + result += dateStr; + result += L'T'; } + { + wchar_t timeStr[buffSize] = {0}; #if _WIN32_WINNT < _WIN32_WINNT_VISTA - TCHAR timeStr[buffSize] = {0}; - status = GetTimeFormat(LOCALE_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, __TEXT("HH':'mm':'ss"), timeStr, buffSize); + status = GetTimeFormatW(LOCALE_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L"HH':'mm':'ss", timeStr, buffSize); #else - wchar_t timeStr[buffSize] = {0}; - status = GetTimeFormatEx(LOCALE_NAME_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L"HH':'mm':'ss", timeStr, buffSize); + status = GetTimeFormatEx(LOCALE_NAME_INVARIANT, TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &systemTime, L"HH':'mm':'ss", timeStr, buffSize); #endif // _WIN32_WINNT < _WIN32_WINNT_VISTA - if (status == 0) - { - throw utility::details::create_system_error(GetLastError()); + if (status == 0) + { + throw utility::details::create_system_error(GetLastError()); + } + + result += timeStr; } - outStream << dateStr << "T" << timeStr; + uint64_t frac_sec = largeInt.QuadPart % _secondTicks; if (frac_sec > 0) { // Append fractional second, which is a 7-digit value with no trailing zeros // This way, '1200' becomes '00012' - char buf[9] = { 0 }; - sprintf_s(buf, sizeof(buf), ".%07ld", (long int)frac_sec); - // trim trailing zeros - for (int i = 7; buf[i] == '0'; i--) buf[i] = '\0'; - outStream << buf; + wchar_t buf[9] = { 0 }; + size_t appended = swprintf_s(buf, 9, L".%07ld", static_cast(frac_sec)); + while (buf[appended - 1] == L'0') --appended; // trim trailing zeros + result.append(buf, appended); } - outStream << "Z"; + + result += L'Z'; } - return outStream.str(); + return result; #else //LINUX uint64_t input = m_interval; uint64_t frac_sec = input % _secondTicks; @@ -1103,33 +1114,44 @@ utility::string_t __cdecl timespan::seconds_to_xml_duration(utility::seconds dur // The format is: // PdaysDThoursHminutesMsecondsS - utility::ostringstream_t oss; - oss.imbue(std::locale::classic()); - - oss << _XPLATSTR("P"); + utility::string_t result; + // (approximate mins/hours/secs as 2 digits each + 1 prefix character) + 1 for P prefix + 1 for T + size_t baseReserveSize = ((numHours > 0) + (numMins > 0) + (numSecs > 0)) * 3 + 1; if (numDays > 0) { - oss << numDays << _XPLATSTR("D"); + utility::string_t daysStr = utility::conversions::details::to_string_t(numDays); + result.reserve(baseReserveSize + daysStr.size() + 1); + result += _XPLATSTR('P'); + result += daysStr; + result += _XPLATSTR('D'); + } + else + { + result.reserve(baseReserveSize); + result += _XPLATSTR('P'); } - oss << _XPLATSTR("T"); + result += _XPLATSTR('T'); if (numHours > 0) { - oss << numHours << _XPLATSTR("H"); + result += utility::conversions::details::to_string_t(numHours); + result += _XPLATSTR('H'); } if (numMins > 0) { - oss << numMins << _XPLATSTR("M"); + result += utility::conversions::details::to_string_t(numMins); + result += _XPLATSTR('M'); } if (numSecs > 0) { - oss << numSecs << _XPLATSTR("S"); + result += utility::conversions::details::to_string_t(numSecs); + result += _XPLATSTR('S'); } - return oss.str(); + return result; } utility::seconds __cdecl timespan::xml_duration_to_seconds(const utility::string_t ×panString) diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index 39b7121d57..c4c46941ba 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -97,12 +97,12 @@ namespace details // Utility function to build up error string based on error code and location. static std::string build_error_msg(const std::error_code &ec, const std::string &location) { - std::stringstream ss; - ss.imbue(std::locale::classic()); - ss << location - << ": " << ec.value() - << ": " << ec.message(); - return ss.str(); + std::string result = location; + result += ": "; + result += std::to_string(ec.value()); + result += ": "; + result += ec.message(); + return result; } static utility::string_t g_subProtocolHeader(_XPLATSTR("Sec-WebSocket-Protocol")); diff --git a/Release/src/websockets/client/ws_msg.cpp b/Release/src/websockets/client/ws_msg.cpp index 1d24409c67..ee27cde01f 100644 --- a/Release/src/websockets/client/ws_msg.cpp +++ b/Release/src/websockets/client/ws_msg.cpp @@ -45,7 +45,7 @@ std::vector<::utility::string_t> websocket_client_config::subprotocols() const auto subprotocolHeader = m_headers.find(g_subProtocolHeader); if (subprotocolHeader != m_headers.end()) { - utility::stringstream_t header(subprotocolHeader->second); + utility::istringstream_t header(subprotocolHeader->second); utility::string_t token; while (std::getline(header, token, U(','))) { diff --git a/Release/tests/functional/http/client/compression_tests.cpp b/Release/tests/functional/http/client/compression_tests.cpp index 10e37186fa..fd9142931a 100644 --- a/Release/tests/functional/http/client/compression_tests.cpp +++ b/Release/tests/functional/http/client/compression_tests.cpp @@ -55,17 +55,14 @@ SUITE(compression_tests) size_t output_size, web::http::compression::operation_hint hint, size_t& input_bytes_processed, - bool* done) + bool& done) { size_t bytes; if (_done) { input_bytes_processed = 0; - if (done) - { - *done = true; - } + done = true; return 0; } if (_size == static_cast(-1) || input_size > _size - _so_far) @@ -82,10 +79,7 @@ SUITE(compression_tests) } _so_far += bytes; _done = (_so_far == _size); - if (done) - { - *done = _done; - } + done = _done; input_bytes_processed = bytes; return input_bytes_processed; } @@ -102,7 +96,7 @@ SUITE(compression_tests) try { r.output_bytes_produced = - decompress(input, input_size, output, output_size, hint, r.input_bytes_processed, &r.done); + decompress(input, input_size, output, output_size, hint, r.input_bytes_processed, r.done); } catch (...) { @@ -120,17 +114,14 @@ SUITE(compression_tests) size_t output_size, web::http::compression::operation_hint hint, size_t& input_bytes_processed, - bool* done) + bool& done) { size_t bytes; if (_done) { input_bytes_processed = 0; - if (done) - { - *done = true; - } + done = true; return 0; } if (_size == static_cast(-1) || input_size > _size - _so_far) @@ -147,10 +138,7 @@ SUITE(compression_tests) } _so_far += bytes; _done = (hint == web::http::compression::operation_hint::is_last && _so_far == _size); - if (done) - { - *done = _done; - } + done = _done; input_bytes_processed = bytes; return input_bytes_processed; } @@ -167,7 +155,7 @@ SUITE(compression_tests) try { r.output_bytes_produced = - compress(input, input_size, output, output_size, hint, r.input_bytes_processed, &r.done); + compress(input, input_size, output, output_size, hint, r.input_bytes_processed, r.done); } catch (...) { @@ -224,14 +212,17 @@ SUITE(compression_tests) input_buffer.reserve(buffer_size); for (size_t i = 0; i < buffer_size; ++i) { + uint8_t element; if (compressible) { - input_buffer.push_back(static_cast('a' + i % 26)); + element = static_cast('a' + i % 26); } else { - input_buffer.push_back(static_cast(std::rand())); + element = static_cast(std::rand()); } + + input_buffer.push_back(element); } // compress in chunks @@ -869,7 +860,7 @@ SUITE(compression_tests) pre.size(), web::http::compression::operation_hint::is_last, used, - &done); + done); VERIFY_IS_TRUE(used == v.size()); VERIFY_IS_TRUE(done); @@ -1019,7 +1010,7 @@ SUITE(compression_tests) pre.size(), web::http::compression::operation_hint::is_last, used, - &done); + done); VERIFY_ARE_EQUAL(used, v.size()); VERIFY_IS_TRUE(done); @@ -1110,7 +1101,7 @@ SUITE(compression_tests) vv.size(), web::http::compression::operation_hint::is_last, used, - &done); + done); VERIFY_ARE_EQUAL(used, p_request->m_body.size()); VERIFY_IS_TRUE(done); } @@ -1219,7 +1210,7 @@ SUITE(compression_tests) cmp.size() - extra, web::http::compression::operation_hint::is_last, used, - &done); + done); VERIFY_ARE_EQUAL(used, v.size()); VERIFY_IS_TRUE(done); } From b9dd8eab814892f110853be1098df1b3f77b2ff0 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Wed, 10 Oct 2018 20:28:41 -0700 Subject: [PATCH 275/438] Reduce stdafx.h header inclusion to avoid running out of memory on *nix boxes in Pipelines (#906) * Pare down stdafx.h to avoid running out of memory on the Linux builders with ninja. * Remove ninja -j. --- Release/include/cpprest/asyncrt_utils.h | 11 ++++------- Release/src/http/client/http_client_asio.cpp | 1 + Release/src/http/common/http_msg.cpp | 2 ++ Release/src/http/listener/http_server_asio.cpp | 2 ++ .../src/http/listener/http_server_httpsys.cpp | 1 + Release/src/http/oauth/oauth2.cpp | 2 ++ Release/src/pch/stdafx.h | 18 ------------------ Release/src/pplx/pplxlinux.cpp | 1 + Release/src/uri/uri.cpp | 2 ++ Release/src/uri/uri_builder.cpp | 10 ++++++---- Release/src/utilities/asyncrt_utils.cpp | 1 + Release/src/websockets/client/ws_client.cpp | 3 ++- .../src/websockets/client/ws_client_wspp.cpp | 1 + Release/src/websockets/client/ws_msg.cpp | 3 +++ azure-pipelines.yml | 8 ++++---- 15 files changed, 32 insertions(+), 34 deletions(-) diff --git a/Release/include/cpprest/asyncrt_utils.h b/Release/include/cpprest/asyncrt_utils.h index 2739a13e35..03bd6fbf90 100644 --- a/Release/include/cpprest/asyncrt_utils.h +++ b/Release/include/cpprest/asyncrt_utils.h @@ -13,20 +13,17 @@ #pragma once -#include -#include +#include #include -#include #include +#include +#include +#include #include #include #include "pplx/pplxtasks.h" #include "cpprest/details/basic_types.h" -#if !defined(_WIN32) || (_MSC_VER >= 1700) -#include -#endif - #ifndef _WIN32 #include #if !defined(ANDROID) && !defined(__ANDROID__) && defined(HAVE_XLOCALE_H) // CodePlex 269 diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 7ee22133fe..645b45466c 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -14,6 +14,7 @@ ****/ #include "stdafx.h" +#include #include "../common/internal_http_helpers.h" #include "cpprest/asyncrt_utils.h" diff --git a/Release/src/http/common/http_msg.cpp b/Release/src/http/common/http_msg.cpp index 44870f5420..91da2c2c3e 100644 --- a/Release/src/http/common/http_msg.cpp +++ b/Release/src/http/common/http_msg.cpp @@ -11,7 +11,9 @@ * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #include "stdafx.h" +#include #include "../common/internal_http_helpers.h" +#include "cpprest/producerconsumerstream.h" using namespace web; using namespace utility; diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp index 5ab3086954..591e623d82 100644 --- a/Release/src/http/listener/http_server_asio.cpp +++ b/Release/src/http/listener/http_server_asio.cpp @@ -14,6 +14,8 @@ */ #include "stdafx.h" +#include +#include #include #include #include diff --git a/Release/src/http/listener/http_server_httpsys.cpp b/Release/src/http/listener/http_server_httpsys.cpp index 242dae4800..9cde3f522e 100644 --- a/Release/src/http/listener/http_server_httpsys.cpp +++ b/Release/src/http/listener/http_server_httpsys.cpp @@ -14,6 +14,7 @@ ****/ #include "stdafx.h" +#include "cpprest/rawptrstream.h" #if _WIN32_WINNT >= _WIN32_WINNT_VISTA diff --git a/Release/src/http/oauth/oauth2.cpp b/Release/src/http/oauth/oauth2.cpp index c85cf44c2f..f37f876dbc 100644 --- a/Release/src/http/oauth/oauth2.cpp +++ b/Release/src/http/oauth/oauth2.cpp @@ -13,6 +13,8 @@ #include "stdafx.h" +#include + using web::http::client::http_client; using web::http::client::http_client_config; using web::http::oauth2::details::oauth2_strings; diff --git a/Release/src/pch/stdafx.h b/Release/src/pch/stdafx.h index 93ad966509..dc909d5afd 100644 --- a/Release/src/pch/stdafx.h +++ b/Release/src/pch/stdafx.h @@ -49,8 +49,6 @@ #include #include #include -#include -#include #include #include #include "pthread.h" @@ -75,19 +73,14 @@ // This is to help track how many developers are directly building from source themselves. #define _CASA_BUILD_FROM_SRC -#include -#include #include #include #include -#include #include #include #include #include #include -#include -#include #include "cpprest/details/cpprest_compat.h" #include "cpprest/details/basic_types.h" @@ -95,13 +88,6 @@ #include "pplx/pplxtasks.h" #include "cpprest/version.h" -// streams -#include "cpprest/streams.h" -#include "cpprest/astreambuf.h" -#include "cpprest/rawptrstream.h" -#include "cpprest/interopstream.h" -#include "cpprest/producerconsumerstream.h" - // json #include "cpprest/json.h" @@ -124,10 +110,6 @@ #endif #include "cpprest/oauth2.h" -// websockets -#include "cpprest/ws_client.h" -#include "cpprest/ws_msg.h" - #if !defined(__cplusplus_winrt) #if _WIN32_WINNT >= _WIN32_WINNT_VISTA #include "cpprest/details/http_server.h" diff --git a/Release/src/pplx/pplxlinux.cpp b/Release/src/pplx/pplxlinux.cpp index b2dc524c86..50365794a3 100644 --- a/Release/src/pplx/pplxlinux.cpp +++ b/Release/src/pplx/pplxlinux.cpp @@ -15,6 +15,7 @@ #include "pplx/pplx.h" #include "pplx/threadpool.h" #include "sys/syscall.h" +#include #ifdef _WIN32 #error "ERROR: This file should only be included in non-windows Build" diff --git a/Release/src/uri/uri.cpp b/Release/src/uri/uri.cpp index fac048c9da..eaacb5ccfd 100644 --- a/Release/src/uri/uri.cpp +++ b/Release/src/uri/uri.cpp @@ -13,6 +13,8 @@ #include "stdafx.h" +#include + using namespace utility::conversions; namespace web { namespace details diff --git a/Release/src/uri/uri_builder.cpp b/Release/src/uri/uri_builder.cpp index 02dd024b9b..f99923c487 100644 --- a/Release/src/uri/uri_builder.cpp +++ b/Release/src/uri/uri_builder.cpp @@ -13,6 +13,8 @@ #include "stdafx.h" +#include + namespace web { @@ -120,8 +122,8 @@ bool uri_builder::is_valid() return uri::validate(m_uri.join()); } -void uri_builder::append_query_encode_impl(const utility::string_t & name, const utf8string & value) -{ +void uri_builder::append_query_encode_impl(const utility::string_t & name, const utf8string & value) +{ utility::string_t encodedQuery = uri::encode_query_impl(utility::conversions::to_utf8string(name)); encodedQuery.append(_XPLATSTR("=")); encodedQuery.append(uri::encode_query_impl(value)); @@ -130,8 +132,8 @@ void uri_builder::append_query_encode_impl(const utility::string_t & name, const append_query(encodedQuery, false); } -void uri_builder::append_query_no_encode_impl(const utility::string_t & name, const utility::string_t & value) -{ +void uri_builder::append_query_no_encode_impl(const utility::string_t & name, const utility::string_t & value) +{ append_query(name + _XPLATSTR("=") + value, false); } diff --git a/Release/src/utilities/asyncrt_utils.cpp b/Release/src/utilities/asyncrt_utils.cpp index 3903ce9ca7..eb20f91f0e 100644 --- a/Release/src/utilities/asyncrt_utils.cpp +++ b/Release/src/utilities/asyncrt_utils.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #ifndef _WIN32 #if defined(__clang__) diff --git a/Release/src/websockets/client/ws_client.cpp b/Release/src/websockets/client/ws_client.cpp index 4caceb3b2e..1d829eb746 100644 --- a/Release/src/websockets/client/ws_client.cpp +++ b/Release/src/websockets/client/ws_client.cpp @@ -9,6 +9,7 @@ * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #include "stdafx.h" +#include "cpprest/ws_client.h" #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) @@ -91,4 +92,4 @@ pplx::task websocket_client_task_impl::receive() }}}} -#endif \ No newline at end of file +#endif diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index c4c46941ba..5ba93d25eb 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -12,6 +12,7 @@ ****/ #include "stdafx.h" +#include #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) diff --git a/Release/src/websockets/client/ws_msg.cpp b/Release/src/websockets/client/ws_msg.cpp index ee27cde01f..c9a5bea8ae 100644 --- a/Release/src/websockets/client/ws_msg.cpp +++ b/Release/src/websockets/client/ws_msg.cpp @@ -13,6 +13,9 @@ * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #include "stdafx.h" +#include +#include "cpprest/ws_client.h" +#include "cpprest/ws_msg.h" #include "../../http/common/internal_http_helpers.h" #if !defined(CPPREST_EXCLUDE_WEBSOCKETS) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d984c4094e..f40964713a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -18,7 +18,7 @@ jobs: cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Debug ..' - script: | cd build.debug - ninja -j 4 + ninja displayName: 'Run ninja' - script: | cd build.debug/Release/Binaries @@ -41,7 +41,7 @@ jobs: cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Release ..' - script: | cd build.release - ninja -j 4 + ninja displayName: 'Run ninja' - script: | cd build.release/Release/Binaries @@ -61,7 +61,7 @@ jobs: cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Debug ..' - script: | cd build.debug - ninja -j 4 + ninja displayName: 'Run ninja' - script: | cd build.debug/Release/Binaries @@ -81,7 +81,7 @@ jobs: cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Release ..' - script: | cd build.release - ninja -j 4 + ninja displayName: 'Run ninja' - script: | cd build.release/Release/Binaries From a072579126e3dfb750f489785b85f5752239f53e Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Fri, 12 Oct 2018 13:26:32 -0700 Subject: [PATCH 276/438] Add Windows CI to Pipelines using vcpkg for dependencies; merge debug and release for other platforms. (#911) --- .gitmodules | 3 + azure-pipelines.yml | 219 +++++++++++++++++++++++++++++++++++--------- vcpkg | 1 + 3 files changed, 182 insertions(+), 41 deletions(-) create mode 100644 .gitmodules create mode 160000 vcpkg diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..3c19d8d07f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "vcpkg"] + path = vcpkg + url = https://github.com/Microsoft/vcpkg diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f40964713a..bb52036b90 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,30 +1,135 @@ # CppRestSdk Azure Pipelines Configuration jobs: - - job: Ubuntu_1604_Apt_Debug + - job: Windows_VS2017_x86 pool: - vmImage: 'Ubuntu 16.04' + vmImage: 'vs2017-win2016' steps: + - script: .\vcpkg\bootstrap-vcpkg.bat + displayName: Bootstrap vcpkg + - script: .\vcpkg\vcpkg.exe install zlib openssl boost-system boost-date-time boost-regex boost-interprocess websocketpp + displayName: vcpkg install dependencies + - script: mkdir build.common + displayName: Make Build Directory + - task: CMake@1 + inputs: + workingDirectory: 'build.common' + cmakeArgs: '-DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + - task: MSBuild@1 + inputs: + solution: 'build.common/ALL_BUILD.vcxproj' + maximumCpuCount: true - script: | - sudo apt-get install -y ppa-purge - sudo ppa-purge -y ppa:ondrej/php - sudo apt-get install -y libboost-atomic-dev libboost-thread-dev libboost-system-dev libboost-date-time-dev libboost-regex-dev libboost-filesystem-dev libboost-random-dev libboost-chrono-dev libboost-serialization-dev libwebsocketpp-dev brotli openssl libssl-dev ninja-build - displayName: Apt install dependencies - - script: mkdir build.debug - displayName: Make build.debug + cd build.common\Release\Binaries\Debug + .\test_runner.exe *testd.dll + displayName: 'Run tests, debug' + - task: MSBuild@1 + inputs: + solution: 'build.common/ALL_BUILD.vcxproj' + maximumCpuCount: true + configuration: 'Release' + - script: | + cd build.common\Release\Binaries\Release + .\test_runner.exe *test.dll + displayName: 'Run tests, release' + - job: Windows_VS2017_x64 + pool: + vmImage: 'vs2017-win2016' + steps: + - script: .\vcpkg\bootstrap-vcpkg.bat + displayName: Bootstrap vcpkg + - script: .\vcpkg\vcpkg.exe install zlib openssl boost-system boost-date-time boost-regex boost-interprocess websocketpp --triplet x64-windows + displayName: vcpkg install dependencies + - script: mkdir build.common + displayName: Make Build Directory - task: CMake@1 inputs: - workingDirectory: 'build.debug' - cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Debug ..' + workingDirectory: 'build.common' + cmakeArgs: '-A x64 -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + - task: MSBuild@1 + inputs: + solution: 'build.common/ALL_BUILD.vcxproj' + maximumCpuCount: true + platform: 'x64' - script: | - cd build.debug - ninja - displayName: 'Run ninja' + cd build.common\Release\Binaries\Debug + .\test_runner.exe *testd.dll + displayName: 'Run tests, debug' + - task: MSBuild@1 + inputs: + solution: 'build.common/ALL_BUILD.vcxproj' + maximumCpuCount: true + platform: 'x64' + configuration: 'Release' - script: | - cd build.debug/Release/Binaries - ./test_runner *test.so - displayName: 'Run Tests' - - job: Ubuntu_1604_Apt_Release + cd build.common\Release\Binaries\Release + .\test_runner.exe *test.dll + displayName: 'Run tests, release' + - job: Windows_VS2015_x86 + pool: + vmImage: 'vs2015-win2012r2' + steps: + - script: .\vcpkg\bootstrap-vcpkg.bat + displayName: Bootstrap vcpkg + - script: .\vcpkg\vcpkg.exe install zlib openssl boost-system boost-date-time boost-regex boost-interprocess websocketpp + displayName: vcpkg install dependencies + - script: mkdir build.common + displayName: Make Build Directory + - task: CMake@1 + inputs: + workingDirectory: 'build.common' + cmakeArgs: '-DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + - task: MSBuild@1 + inputs: + solution: 'build.common/ALL_BUILD.vcxproj' + maximumCpuCount: true + - script: | + cd build.common\Release\Binaries\Debug + .\test_runner.exe *testd.dll + displayName: 'Run tests, debug' + - task: MSBuild@1 + inputs: + solution: 'build.common/ALL_BUILD.vcxproj' + maximumCpuCount: true + configuration: 'Release' + - script: | + cd build.common\Release\Binaries\Release + .\test_runner.exe *test.dll + displayName: 'Run tests, release' + - job: Windows_VS2015_x64 + pool: + vmImage: 'vs2015-win2012r2' + steps: + - script: .\vcpkg\bootstrap-vcpkg.bat + displayName: Bootstrap vcpkg + - script: .\vcpkg\vcpkg.exe install zlib openssl boost-system boost-date-time boost-regex boost-interprocess websocketpp --triplet x64-windows + displayName: vcpkg install dependencies + - script: mkdir build.common + displayName: Make Build Directory + - task: CMake@1 + inputs: + workingDirectory: 'build.common' + cmakeArgs: '-A x64 -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + - task: MSBuild@1 + inputs: + solution: 'build.common/ALL_BUILD.vcxproj' + maximumCpuCount: true + platform: 'x64' + - script: | + cd build.common\Release\Binaries\Debug + .\test_runner.exe *testd.dll + displayName: 'Run tests, debug' + - task: MSBuild@1 + inputs: + solution: 'build.common/ALL_BUILD.vcxproj' + maximumCpuCount: true + platform: 'x64' + configuration: 'Release' + - script: | + cd build.common\Release\Binaries\Release + .\test_runner.exe *test.dll + displayName: 'Run tests, release' + - job: Ubuntu_1604_Apt pool: vmImage: 'Ubuntu 16.04' steps: @@ -33,57 +138,89 @@ jobs: sudo ppa-purge -y ppa:ondrej/php sudo apt-get install -y libboost-atomic-dev libboost-thread-dev libboost-system-dev libboost-date-time-dev libboost-regex-dev libboost-filesystem-dev libboost-random-dev libboost-chrono-dev libboost-serialization-dev libwebsocketpp-dev brotli openssl libssl-dev ninja-build displayName: Apt install dependencies - - script: mkdir build.release - displayName: Make build.release + - script: | + mkdir build.debug + mkdir build.release + displayName: Make Build Directories + - task: CMake@1 + inputs: + workingDirectory: 'build.debug' + cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Debug ..' - task: CMake@1 inputs: workingDirectory: 'build.release' cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Release ..' + - script: | + cd build.debug + ninja + displayName: 'Run ninja, debug' + - script: | + cd build.debug/Release/Binaries + ./test_runner *test.so + displayName: 'Run tests, debug' - script: | cd build.release ninja - displayName: 'Run ninja' + displayName: 'Run ninja, release' - script: | cd build.release/Release/Binaries ./test_runner *test.so - displayName: 'Run Tests' - - job: MacOS_Debug + displayName: 'Run tests, release' + + # vcpkg on Linux missing for now due to OpenSSL root certificates + # - job: Ubuntu_1604_Vcpkg_Debug + # pool: + # vmImage: 'Ubuntu 16.04' + # steps: + # - script: | + # ./vcpkg/bootstrap-vcpkg.sh + # ./vcpkg/vcpkg install zlib openssl boost-system boost-date-time boost-regex websocketpp boost-thread boost-filesystem boost-random boost-chrono + # displayName: Apt install dependencies + # - script: mkdir build.debug + # displayName: Make build.debug + # - task: CMake@1 + # inputs: + # workingDirectory: 'build.debug' + # cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + # - script: | + # cd build.debug + # ninja + # displayName: 'Run ninja' + # - script: | + # cd build.debug/Release/Binaries + # ./test_runner *test.so + # displayName: 'Run Tests' + - job: MacOS pool: vmImage: 'macOS-10.13' steps: - script: brew install boost openssl ninja - displayName: Berw install dependencies - - script: mkdir build.debug - displayName: Make build.debug + displayName: Brew install dependencies + - script: | + mkdir build.debug + mkdir build.release + displayName: Make Build Directories - task: CMake@1 inputs: workingDirectory: 'build.debug' cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Debug ..' + - task: CMake@1 + inputs: + workingDirectory: 'build.release' + cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Release ..' - script: | cd build.debug ninja - displayName: 'Run ninja' + displayName: 'Run ninja, debug' - script: | cd build.debug/Release/Binaries ./test_runner *test.dylib - displayName: 'Run Tests' - - job: MacOS_Release - pool: - vmImage: 'macOS-10.13' - steps: - - script: brew install boost openssl ninja - displayName: Berw install dependencies - - script: mkdir build.release - displayName: Make build.release - - task: CMake@1 - inputs: - workingDirectory: 'build.release' - cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Release ..' + displayName: 'Run tests, debug' - script: | cd build.release ninja - displayName: 'Run ninja' + displayName: 'Run ninja, release' - script: | cd build.release/Release/Binaries ./test_runner *test.dylib - displayName: 'Run Tests' + displayName: 'Run tests, release' diff --git a/vcpkg b/vcpkg new file mode 160000 index 0000000000..29858b3cb2 --- /dev/null +++ b/vcpkg @@ -0,0 +1 @@ +Subproject commit 29858b3cb2c8a0ec2c85b1b14d6d0a0d1dfe309e From 61b1699af21740a2fb5bc8f4d2b81494a4b220e8 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Fri, 12 Oct 2018 16:58:01 -0700 Subject: [PATCH 277/438] Enable Brotli in CI. (#912) * Enable Brotli in CI. --- Release/src/http/common/http_compression.cpp | 4 +-- azure-pipelines.yml | 27 +++++++++++++------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/Release/src/http/common/http_compression.cpp b/Release/src/http/common/http_compression.cpp index 9d409906c5..d73167239b 100644 --- a/Release/src/http/common/http_compression.cpp +++ b/Release/src/http/common/http_compression.cpp @@ -383,7 +383,7 @@ class brotli_compressor : public compress_provider try { r.output_bytes_produced = - compress(input, input_size, output, output_size, hint, r.input_bytes_processed, &r.done); + compress(input, input_size, output, output_size, hint, r.input_bytes_processed, r.done); } catch (...) { @@ -509,7 +509,7 @@ class brotli_decompressor : public decompress_provider try { r.output_bytes_produced = - decompress(input, input_size, output, output_size, hint, r.input_bytes_processed, &r.done); + decompress(input, input_size, output, output_size, hint, r.input_bytes_processed, r.done); } catch (...) { diff --git a/azure-pipelines.yml b/azure-pipelines.yml index bb52036b90..76766a59b4 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,14 +7,14 @@ jobs: steps: - script: .\vcpkg\bootstrap-vcpkg.bat displayName: Bootstrap vcpkg - - script: .\vcpkg\vcpkg.exe install zlib openssl boost-system boost-date-time boost-regex boost-interprocess websocketpp + - script: .\vcpkg\vcpkg.exe install zlib openssl boost-system boost-date-time boost-regex boost-interprocess websocketpp brotli displayName: vcpkg install dependencies - script: mkdir build.common displayName: Make Build Directory - task: CMake@1 inputs: workingDirectory: 'build.common' - cmakeArgs: '-DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + cmakeArgs: '-DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCPPREST_EXCLUDE_BROTLI=OFF ..' - task: MSBuild@1 inputs: solution: 'build.common/ALL_BUILD.vcxproj' @@ -38,14 +38,14 @@ jobs: steps: - script: .\vcpkg\bootstrap-vcpkg.bat displayName: Bootstrap vcpkg - - script: .\vcpkg\vcpkg.exe install zlib openssl boost-system boost-date-time boost-regex boost-interprocess websocketpp --triplet x64-windows + - script: .\vcpkg\vcpkg.exe install zlib openssl boost-system boost-date-time boost-regex boost-interprocess websocketpp brotli --triplet x64-windows displayName: vcpkg install dependencies - script: mkdir build.common displayName: Make Build Directory - task: CMake@1 inputs: workingDirectory: 'build.common' - cmakeArgs: '-A x64 -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + cmakeArgs: '-A x64 -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCPPREST_EXCLUDE_BROTLI=OFF ..' - task: MSBuild@1 inputs: solution: 'build.common/ALL_BUILD.vcxproj' @@ -71,14 +71,14 @@ jobs: steps: - script: .\vcpkg\bootstrap-vcpkg.bat displayName: Bootstrap vcpkg - - script: .\vcpkg\vcpkg.exe install zlib openssl boost-system boost-date-time boost-regex boost-interprocess websocketpp + - script: .\vcpkg\vcpkg.exe install zlib openssl boost-system boost-date-time boost-regex boost-interprocess websocketpp brotli displayName: vcpkg install dependencies - script: mkdir build.common displayName: Make Build Directory - task: CMake@1 inputs: workingDirectory: 'build.common' - cmakeArgs: '-DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + cmakeArgs: '-DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCPPREST_EXCLUDE_BROTLI=OFF ..' - task: MSBuild@1 inputs: solution: 'build.common/ALL_BUILD.vcxproj' @@ -102,14 +102,14 @@ jobs: steps: - script: .\vcpkg\bootstrap-vcpkg.bat displayName: Bootstrap vcpkg - - script: .\vcpkg\vcpkg.exe install zlib openssl boost-system boost-date-time boost-regex boost-interprocess websocketpp --triplet x64-windows + - script: .\vcpkg\vcpkg.exe install zlib openssl boost-system boost-date-time boost-regex boost-interprocess websocketpp brotli --triplet x64-windows displayName: vcpkg install dependencies - script: mkdir build.common displayName: Make Build Directory - task: CMake@1 inputs: workingDirectory: 'build.common' - cmakeArgs: '-A x64 -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + cmakeArgs: '-A x64 -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake -DCPPREST_EXCLUDE_BROTLI=OFF ..' - task: MSBuild@1 inputs: solution: 'build.common/ALL_BUILD.vcxproj' @@ -136,7 +136,7 @@ jobs: - script: | sudo apt-get install -y ppa-purge sudo ppa-purge -y ppa:ondrej/php - sudo apt-get install -y libboost-atomic-dev libboost-thread-dev libboost-system-dev libboost-date-time-dev libboost-regex-dev libboost-filesystem-dev libboost-random-dev libboost-chrono-dev libboost-serialization-dev libwebsocketpp-dev brotli openssl libssl-dev ninja-build + sudo apt-get install -y libboost-atomic-dev libboost-thread-dev libboost-system-dev libboost-date-time-dev libboost-regex-dev libboost-filesystem-dev libboost-random-dev libboost-chrono-dev libboost-serialization-dev libwebsocketpp-dev openssl libssl-dev ninja-build displayName: Apt install dependencies - script: | mkdir build.debug @@ -199,6 +199,7 @@ jobs: - script: | mkdir build.debug mkdir build.release + mkdir build.release.static displayName: Make Build Directories - task: CMake@1 inputs: @@ -208,6 +209,10 @@ jobs: inputs: workingDirectory: 'build.release' cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Release ..' + - task: CMake@1 + inputs: + workingDirectory: 'build.release.static' + cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF ..' - script: | cd build.debug ninja @@ -224,3 +229,7 @@ jobs: cd build.release/Release/Binaries ./test_runner *test.dylib displayName: 'Run tests, release' + - script: | + cd build.release.static + ninja + displayName: 'Run ninja, release static' From 8a1eec818a86ee9372ca89f976ffa982d4591a9f Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Sun, 14 Oct 2018 15:02:28 -0700 Subject: [PATCH 278/438] Restore PCHes and delete unmaintained / broken legacy project files. (#914) --- Build/Common.Build.Traversal.targets | 28 -- Build/Common.Build.settings | 242 ---------- Build/Config.Definitions.props | 29 -- Build/Release.Product.settings | 64 --- Build/Release.Tests.settings | 27 -- Build/version.props | 11 - NuGet.Config | 6 - .../BingRequest140.xp.vcxproj | 133 ------ .../BingRequest140.xp.vcxproj.filters | 13 - .../BingRequest140/BingRequest140.vcxproj | 141 ------ .../BingRequest140.vcxproj.filters | 13 - .../BingRequest141/BingRequest141.vcxproj | 134 ------ .../BingRequest141.vcxproj.filters | 12 - .../BlackJack_Client/BlackJackClient.cpp | 31 +- .../BlackJack_Client140.vcxproj | 148 ------ .../BlackJack_Client140.vcxproj.filters | 33 -- .../BlackJack_Client141.vcxproj | 149 ------ .../BlackJack_Client141.vcxproj.filters | 30 -- .../BlackJack/BlackJack_Client/CMakeLists.txt | 1 - .../BlackJack/BlackJack_Client/stdafx.cpp | 15 - .../BlackJack/BlackJack_Client/stdafx.h | 44 -- .../BlackJack/BlackJack_Client/targetver.h | 18 - .../BlackJack_Server140.vcxproj | 154 ------ .../BlackJack_Server140.vcxproj.filters | 45 -- .../BlackJack_Server141.vcxproj | 155 ------- .../BlackJack_Server141.vcxproj.filters | 42 -- .../BlackJack/BlackJack_Server/CMakeLists.txt | 12 +- Release/samples/Oauth1Client/CMakeLists.txt | 5 +- Release/samples/Oauth1Client/Oauth1Client.cpp | 4 +- .../Oauth1Client140/Oauth1Client140.vcxproj | 205 -------- .../Oauth1Client140.vcxproj.filters | 33 -- .../Oauth1Client141/Oauth1Client141.vcxproj | 206 --------- .../Oauth1Client141.vcxproj.filters | 33 -- Release/samples/Oauth1Client/stdafx.cpp | 15 - Release/samples/Oauth1Client/stdafx.h | 17 - Release/samples/Oauth2Client/CMakeLists.txt | 3 +- Release/samples/Oauth2Client/Oauth2Client.cpp | 4 +- .../Oauth2Client140/Oauth2Client140.vcxproj | 205 -------- .../Oauth2Client140.vcxproj.filters | 33 -- .../Oauth2Client141/Oauth2Client141.vcxproj | 206 --------- .../Oauth2Client141.vcxproj.filters | 33 -- Release/samples/Oauth2Client/stdafx.cpp | 15 - Release/samples/Oauth2Client/stdafx.h | 17 - .../SearchFile140/SearchFile140.vcxproj | 146 ------ .../SearchFile140.vcxproj.filters | 13 - .../SearchFile141/SearchFile141.vcxproj | 147 ------ .../SearchFile141.vcxproj.filters | 13 - Release/src/CMakeLists.txt | 2 +- Release/src/build/android.vcxitems | 31 -- Release/src/build/android.vcxitems.filters | 39 -- Release/src/build/common.vcxitems | 93 ---- Release/src/build/common.vcxitems.filters | 227 --------- Release/src/build/cpprest.natvis | 207 --------- Release/src/build/init.ps1 | 23 - Release/src/build/other.vcxitems | 22 - Release/src/build/other.vcxitems.filters | 16 - .../casablanca140.android.vcxproj | 138 ------ .../src/build/vs14.android/packages.config | 11 - .../vs14.static/casablanca140.static.vcxproj | 84 ---- Release/src/build/vs14.static/packages.config | 11 - .../cpprestsdk140.uwp.staticlib.vcxproj | 110 ----- .../build/vs14.uwp/cpprestsdk140.uwp.vcxproj | 99 ---- .../build/vs14.xp/casablanca140.xp.vcxproj | 86 ---- Release/src/build/vs14.xp/packages.config | 11 - Release/src/build/vs14/casablanca140.vcxproj | 78 ---- Release/src/build/vs14/packages.config | 11 - .../vs141.android/cpprest141.android.vcxproj | 140 ------ .../src/build/vs141.android/packages.config | 11 - .../build/vs141.uwp/cpprest141.uwp.vcxproj | 91 ---- Release/src/build/vs141/cpprest141.vcxproj | 85 ---- Release/src/build/vs141/packages.config | 11 - Release/src/build/win32.vcxitems | 33 -- Release/src/build/win32.vcxitems.filters | 39 -- Release/src/build/winrt.vcxitems | 31 -- Release/src/build/winrt.vcxitems.filters | 33 -- .../ios/ios_runner.xcodeproj/project.pbxproj | 368 --------------- .../contents.xcworkspacedata | 7 - .../xcschemes/ios_runner.xcscheme | 110 ----- .../TestRunner/ios/ios_runnerTests/Info.plist | 24 - .../ios/ios_runnerTests/ios_runnerTests.mm | 67 --- .../TestRunner.android.NativeActivity.vcxproj | 284 ------------ ...ner.android.NativeActivity.vcxproj.filters | 14 - .../android_native_app_glue.c | 426 ----------------- .../android_native_app_glue.h | 344 -------------- .../main.cpp | 437 ------------------ .../packages.config | 12 - .../TestRunner.android.NativeActivity/pch.h | 23 - .../AndroidManifest.xml | 30 -- .../TestRunner.android.Packaging.androidproj | 84 ---- .../TestRunner.android.Packaging/build.xml | 82 ---- .../project.properties | 2 - .../res/values/strings.xml | 4 - .../vs14.uwp/TestRunner140.uwp.vcxproj | 118 ----- .../TestRunner140.uwp.vcxproj.filters | 24 - .../TestRunner/vs14/TestRunner140.vcxproj | 248 ---------- .../vs14/TestRunner140.vcxproj.filters | 24 - .../UnitTestpp140.android.vcxproj | 199 -------- .../UnitTestpp140.android.vcxproj.filters | 168 ------- .../vs14.uwp/UnitTestpp140.uwp.vcxproj | 208 --------- .../UnitTestpp140.uwp.vcxproj.filters | 159 ------- .../UnitTestpp/vs14/TestUnitTestpp140.vcxproj | 202 -------- .../vs14/TestUnitTestpp140.vcxproj.filters | 72 --- .../UnitTestpp/vs14/UnitTestpp140.vcxproj | 228 --------- .../vs14/UnitTestpp140.vcxproj.filters | 159 ------- Release/tests/common/utilities/CMakeLists.txt | 1 - .../tests/common/utilities/os_utilities.cpp | 7 +- Release/tests/common/utilities/stdafx.cpp | 18 - Release/tests/common/utilities/stdafx.h | 24 - Release/tests/common/utilities/targetver.h | 20 - .../CommonUtilities140.android.vcxproj | 148 ------ ...CommonUtilities140.android.vcxproj.filters | 36 -- .../vs14.uwp/CommonUtilities140.uwp.vcxproj | 167 ------- .../CommonUtilities140.uwp.vcxproj.filters | 33 -- .../vs14.xp/CommonUtilities140.xp.vcxproj | 150 ------ .../utilities/vs14/CommonUtilities140.vcxproj | 200 -------- .../vs14/CommonUtilities140.vcxproj.filters | 33 -- .../functional/http/client/CMakeLists.txt | 14 +- .../http/client/compression_tests.cpp | 3 +- .../HttpClient140_test.android.vcxproj | 168 ------- ...HttpClient140_test.android.vcxproj.filters | 90 ---- .../http/client/vs14.android/packages.config | 5 - .../vs14.uwp/HttpClient140_test.uwp.vcxproj | 153 ------ .../HttpClient140_test.uwp.vcxproj.filters | 87 ---- .../client/vs14/HttpClient140_test.vcxproj | 240 ---------- .../vs14/HttpClient140_test.vcxproj.filters | 88 ---- .../functional/http/listener/CMakeLists.txt | 12 +- .../HttpListener140_test.android.vcxproj | 160 ------- ...tpListener140_test.android.vcxproj.filters | 66 --- .../vs14/HttpListener140_test.vcxproj | 242 ---------- .../vs14/HttpListener140_test.vcxproj.filters | 63 --- .../HttpTestUtilities140.android.vcxproj | 156 ------- ...tpTestUtilities140.android.vcxproj.filters | 54 --- .../vs14.uwp/HttpTestUtilities140.uwp.vcxproj | 183 -------- .../HttpTestUtilities140.uwp.vcxproj.filters | 51 -- .../vs14/HttpTestUtilities140.vcxproj | 218 --------- .../vs14/HttpTestUtilities140.vcxproj.filters | 51 -- Release/tests/functional/json/CMakeLists.txt | 14 +- .../vs14.android/JSON140_test.android.vcxproj | 154 ------ .../JSON140_test.android.vcxproj.filters | 48 -- .../json/vs14.uwp/JSON140_test.uwp.vcxproj | 128 ----- .../vs14.uwp/JSON140_test.uwp.vcxproj.filters | 42 -- .../json/vs14.xp/JSON140_test.xp.vcxproj | 151 ------ .../functional/json/vs14/JSON140_test.vcxproj | 211 --------- .../json/vs14/JSON140_test.vcxproj.filters | 47 -- .../misc/version/vs14/version140_test.vcxproj | 100 ---- .../functional/pplx/pplx_test/CMakeLists.txt | 14 +- .../vs14.android/pplx140_test.android.vcxproj | 149 ------ .../vs14.uwp/pplx140_test.uwp.vcxproj | 130 ------ .../pplx_test/vs14.xp/pplx140_test.xp.vcxproj | 158 ------- .../pplx/pplx_test/vs14/pplx140_test.vcxproj | 212 --------- .../tests/functional/streams/CMakeLists.txt | 14 +- .../streams140_test.android.vcxproj | 153 ------ .../streams140_test.android.vcxproj.filters | 43 -- .../vs14.uwp/streams140_test.uwp.vcxproj | 137 ------ .../streams140_test.uwp.vcxproj.filters | 45 -- .../vs14.xp/streams140_test.xp.vcxproj | 163 ------- .../streams/vs14/streams140_test.vcxproj | 219 --------- .../vs14/streams140_test.vcxproj.filters | 43 -- Release/tests/functional/uri/CMakeLists.txt | 14 +- .../vs14.android/Uri140_test.android.vcxproj | 156 ------- .../Uri140_test.android.vcxproj.filters | 54 --- .../vs14.uwp/URI140_test.uwp.vcxproj.filters | 57 --- .../uri/vs14.uwp/Uri140_test.uwp.vcxproj | 136 ------ .../uri/vs14.xp/Uri140_test.xp.vcxproj | 155 ------- .../functional/uri/vs14/Uri140_test.vcxproj | 212 --------- .../uri/vs14/Uri140_test.vcxproj.filters | 53 --- Release/tests/functional/utils/CMakeLists.txt | 14 +- .../Utils140_test.android.vcxproj | 152 ------ .../Utils140_test.android.vcxproj.filters | 42 -- .../utils/vs14.uwp/Utils140_test.uwp.vcxproj | 131 ------ .../Utils140_test.uwp.vcxproj.filters | 36 -- .../utils/vs14.xp/Utils140_test.xp.vcxproj | 151 ------ .../utils/vs14/Utils140_test.vcxproj | 208 --------- .../utils/vs14/Utils140_test.vcxproj.filters | 38 -- .../websocketsclient140_test.android.vcxproj | 154 ------ .../websocketsclient140_test.uwp.vcxproj | 127 ----- .../websocketsclient140_test.xp.vcxproj | 123 ----- .../vs14/websocketsclient140_test.vcxproj | 125 ----- .../utilities/vs14.android/packages.config | 5 - ...bsockets_test_utilities140.android.vcxproj | 148 ------ .../utilities/vs14.uwp/packages.config | 7 - .../websockets_test_utilities140.uwp.vcxproj | 147 ------ .../websockets_test_utilities140.xp.vcxproj | 132 ------ .../websockets/utilities/vs14/packages.config | 7 - .../vs14/websockets_test_utilities140.vcxproj | 151 ------ build.root | 1 - cpprestsdk140.sln | 292 ------------ cpprestsdk141.sln | 258 ----------- 188 files changed, 143 insertions(+), 17442 deletions(-) delete mode 100644 Build/Common.Build.Traversal.targets delete mode 100644 Build/Common.Build.settings delete mode 100644 Build/Config.Definitions.props delete mode 100644 Build/Release.Product.settings delete mode 100644 Build/Release.Tests.settings delete mode 100644 Build/version.props delete mode 100644 NuGet.Config delete mode 100644 Release/samples/BingRequest/BingRequest140.xp/BingRequest140.xp.vcxproj delete mode 100644 Release/samples/BingRequest/BingRequest140.xp/BingRequest140.xp.vcxproj.filters delete mode 100644 Release/samples/BingRequest/BingRequest140/BingRequest140.vcxproj delete mode 100644 Release/samples/BingRequest/BingRequest140/BingRequest140.vcxproj.filters delete mode 100644 Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj delete mode 100644 Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj.filters delete mode 100644 Release/samples/BlackJack/BlackJack_Client/BlackJack_Client140/BlackJack_Client140.vcxproj delete mode 100644 Release/samples/BlackJack/BlackJack_Client/BlackJack_Client140/BlackJack_Client140.vcxproj.filters delete mode 100644 Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj delete mode 100644 Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj.filters delete mode 100644 Release/samples/BlackJack/BlackJack_Client/stdafx.cpp delete mode 100644 Release/samples/BlackJack/BlackJack_Client/stdafx.h delete mode 100644 Release/samples/BlackJack/BlackJack_Client/targetver.h delete mode 100644 Release/samples/BlackJack/BlackJack_Server/BlackJack_Server140/BlackJack_Server140.vcxproj delete mode 100644 Release/samples/BlackJack/BlackJack_Server/BlackJack_Server140/BlackJack_Server140.vcxproj.filters delete mode 100644 Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj delete mode 100644 Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj.filters delete mode 100644 Release/samples/Oauth1Client/Oauth1Client140/Oauth1Client140.vcxproj delete mode 100644 Release/samples/Oauth1Client/Oauth1Client140/Oauth1Client140.vcxproj.filters delete mode 100644 Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj delete mode 100644 Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj.filters delete mode 100644 Release/samples/Oauth1Client/stdafx.cpp delete mode 100644 Release/samples/Oauth1Client/stdafx.h delete mode 100644 Release/samples/Oauth2Client/Oauth2Client140/Oauth2Client140.vcxproj delete mode 100644 Release/samples/Oauth2Client/Oauth2Client140/Oauth2Client140.vcxproj.filters delete mode 100644 Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj delete mode 100644 Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj.filters delete mode 100644 Release/samples/Oauth2Client/stdafx.cpp delete mode 100644 Release/samples/Oauth2Client/stdafx.h delete mode 100644 Release/samples/SearchFile/SearchFile140/SearchFile140.vcxproj delete mode 100644 Release/samples/SearchFile/SearchFile140/SearchFile140.vcxproj.filters delete mode 100644 Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj delete mode 100644 Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj.filters delete mode 100644 Release/src/build/android.vcxitems delete mode 100644 Release/src/build/android.vcxitems.filters delete mode 100644 Release/src/build/common.vcxitems delete mode 100644 Release/src/build/common.vcxitems.filters delete mode 100644 Release/src/build/cpprest.natvis delete mode 100644 Release/src/build/init.ps1 delete mode 100644 Release/src/build/other.vcxitems delete mode 100644 Release/src/build/other.vcxitems.filters delete mode 100644 Release/src/build/vs14.android/casablanca140.android.vcxproj delete mode 100644 Release/src/build/vs14.android/packages.config delete mode 100644 Release/src/build/vs14.static/casablanca140.static.vcxproj delete mode 100644 Release/src/build/vs14.static/packages.config delete mode 100644 Release/src/build/vs14.uwp/cpprestsdk140.uwp.staticlib.vcxproj delete mode 100644 Release/src/build/vs14.uwp/cpprestsdk140.uwp.vcxproj delete mode 100644 Release/src/build/vs14.xp/casablanca140.xp.vcxproj delete mode 100644 Release/src/build/vs14.xp/packages.config delete mode 100644 Release/src/build/vs14/casablanca140.vcxproj delete mode 100644 Release/src/build/vs14/packages.config delete mode 100644 Release/src/build/vs141.android/cpprest141.android.vcxproj delete mode 100644 Release/src/build/vs141.android/packages.config delete mode 100644 Release/src/build/vs141.uwp/cpprest141.uwp.vcxproj delete mode 100644 Release/src/build/vs141/cpprest141.vcxproj delete mode 100644 Release/src/build/vs141/packages.config delete mode 100644 Release/src/build/win32.vcxitems delete mode 100644 Release/src/build/win32.vcxitems.filters delete mode 100644 Release/src/build/winrt.vcxitems delete mode 100644 Release/src/build/winrt.vcxitems.filters delete mode 100644 Release/tests/common/TestRunner/ios/ios_runner.xcodeproj/project.pbxproj delete mode 100644 Release/tests/common/TestRunner/ios/ios_runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 Release/tests/common/TestRunner/ios/ios_runner.xcodeproj/xcshareddata/xcschemes/ios_runner.xcscheme delete mode 100644 Release/tests/common/TestRunner/ios/ios_runnerTests/Info.plist delete mode 100644 Release/tests/common/TestRunner/ios/ios_runnerTests/ios_runnerTests.mm delete mode 100644 Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/TestRunner.android.NativeActivity.vcxproj delete mode 100644 Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/TestRunner.android.NativeActivity.vcxproj.filters delete mode 100644 Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/android_native_app_glue.c delete mode 100644 Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/android_native_app_glue.h delete mode 100644 Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/main.cpp delete mode 100644 Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/packages.config delete mode 100644 Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/pch.h delete mode 100644 Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/AndroidManifest.xml delete mode 100644 Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/TestRunner.android.Packaging.androidproj delete mode 100644 Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/build.xml delete mode 100644 Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/project.properties delete mode 100644 Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/res/values/strings.xml delete mode 100644 Release/tests/common/TestRunner/vs14.uwp/TestRunner140.uwp.vcxproj delete mode 100644 Release/tests/common/TestRunner/vs14.uwp/TestRunner140.uwp.vcxproj.filters delete mode 100644 Release/tests/common/TestRunner/vs14/TestRunner140.vcxproj delete mode 100644 Release/tests/common/TestRunner/vs14/TestRunner140.vcxproj.filters delete mode 100644 Release/tests/common/UnitTestpp/vs14.android/UnitTestpp140.android.vcxproj delete mode 100644 Release/tests/common/UnitTestpp/vs14.android/UnitTestpp140.android.vcxproj.filters delete mode 100644 Release/tests/common/UnitTestpp/vs14.uwp/UnitTestpp140.uwp.vcxproj delete mode 100644 Release/tests/common/UnitTestpp/vs14.uwp/UnitTestpp140.uwp.vcxproj.filters delete mode 100644 Release/tests/common/UnitTestpp/vs14/TestUnitTestpp140.vcxproj delete mode 100644 Release/tests/common/UnitTestpp/vs14/TestUnitTestpp140.vcxproj.filters delete mode 100644 Release/tests/common/UnitTestpp/vs14/UnitTestpp140.vcxproj delete mode 100644 Release/tests/common/UnitTestpp/vs14/UnitTestpp140.vcxproj.filters delete mode 100644 Release/tests/common/utilities/stdafx.cpp delete mode 100644 Release/tests/common/utilities/stdafx.h delete mode 100644 Release/tests/common/utilities/targetver.h delete mode 100644 Release/tests/common/utilities/vs14.android/CommonUtilities140.android.vcxproj delete mode 100644 Release/tests/common/utilities/vs14.android/CommonUtilities140.android.vcxproj.filters delete mode 100644 Release/tests/common/utilities/vs14.uwp/CommonUtilities140.uwp.vcxproj delete mode 100644 Release/tests/common/utilities/vs14.uwp/CommonUtilities140.uwp.vcxproj.filters delete mode 100644 Release/tests/common/utilities/vs14.xp/CommonUtilities140.xp.vcxproj delete mode 100644 Release/tests/common/utilities/vs14/CommonUtilities140.vcxproj delete mode 100644 Release/tests/common/utilities/vs14/CommonUtilities140.vcxproj.filters delete mode 100644 Release/tests/functional/http/client/vs14.android/HttpClient140_test.android.vcxproj delete mode 100644 Release/tests/functional/http/client/vs14.android/HttpClient140_test.android.vcxproj.filters delete mode 100644 Release/tests/functional/http/client/vs14.android/packages.config delete mode 100644 Release/tests/functional/http/client/vs14.uwp/HttpClient140_test.uwp.vcxproj delete mode 100644 Release/tests/functional/http/client/vs14.uwp/HttpClient140_test.uwp.vcxproj.filters delete mode 100644 Release/tests/functional/http/client/vs14/HttpClient140_test.vcxproj delete mode 100644 Release/tests/functional/http/client/vs14/HttpClient140_test.vcxproj.filters delete mode 100644 Release/tests/functional/http/listener/vs14.android/HttpListener140_test.android.vcxproj delete mode 100644 Release/tests/functional/http/listener/vs14.android/HttpListener140_test.android.vcxproj.filters delete mode 100644 Release/tests/functional/http/listener/vs14/HttpListener140_test.vcxproj delete mode 100644 Release/tests/functional/http/listener/vs14/HttpListener140_test.vcxproj.filters delete mode 100644 Release/tests/functional/http/utilities/vs14.android/HttpTestUtilities140.android.vcxproj delete mode 100644 Release/tests/functional/http/utilities/vs14.android/HttpTestUtilities140.android.vcxproj.filters delete mode 100644 Release/tests/functional/http/utilities/vs14.uwp/HttpTestUtilities140.uwp.vcxproj delete mode 100644 Release/tests/functional/http/utilities/vs14.uwp/HttpTestUtilities140.uwp.vcxproj.filters delete mode 100644 Release/tests/functional/http/utilities/vs14/HttpTestUtilities140.vcxproj delete mode 100644 Release/tests/functional/http/utilities/vs14/HttpTestUtilities140.vcxproj.filters delete mode 100644 Release/tests/functional/json/vs14.android/JSON140_test.android.vcxproj delete mode 100644 Release/tests/functional/json/vs14.android/JSON140_test.android.vcxproj.filters delete mode 100644 Release/tests/functional/json/vs14.uwp/JSON140_test.uwp.vcxproj delete mode 100644 Release/tests/functional/json/vs14.uwp/JSON140_test.uwp.vcxproj.filters delete mode 100644 Release/tests/functional/json/vs14.xp/JSON140_test.xp.vcxproj delete mode 100644 Release/tests/functional/json/vs14/JSON140_test.vcxproj delete mode 100644 Release/tests/functional/json/vs14/JSON140_test.vcxproj.filters delete mode 100644 Release/tests/functional/misc/version/vs14/version140_test.vcxproj delete mode 100644 Release/tests/functional/pplx/pplx_test/vs14.android/pplx140_test.android.vcxproj delete mode 100644 Release/tests/functional/pplx/pplx_test/vs14.uwp/pplx140_test.uwp.vcxproj delete mode 100644 Release/tests/functional/pplx/pplx_test/vs14.xp/pplx140_test.xp.vcxproj delete mode 100644 Release/tests/functional/pplx/pplx_test/vs14/pplx140_test.vcxproj delete mode 100644 Release/tests/functional/streams/vs14.android/streams140_test.android.vcxproj delete mode 100644 Release/tests/functional/streams/vs14.android/streams140_test.android.vcxproj.filters delete mode 100644 Release/tests/functional/streams/vs14.uwp/streams140_test.uwp.vcxproj delete mode 100644 Release/tests/functional/streams/vs14.uwp/streams140_test.uwp.vcxproj.filters delete mode 100644 Release/tests/functional/streams/vs14.xp/streams140_test.xp.vcxproj delete mode 100644 Release/tests/functional/streams/vs14/streams140_test.vcxproj delete mode 100644 Release/tests/functional/streams/vs14/streams140_test.vcxproj.filters delete mode 100644 Release/tests/functional/uri/vs14.android/Uri140_test.android.vcxproj delete mode 100644 Release/tests/functional/uri/vs14.android/Uri140_test.android.vcxproj.filters delete mode 100644 Release/tests/functional/uri/vs14.uwp/URI140_test.uwp.vcxproj.filters delete mode 100644 Release/tests/functional/uri/vs14.uwp/Uri140_test.uwp.vcxproj delete mode 100644 Release/tests/functional/uri/vs14.xp/Uri140_test.xp.vcxproj delete mode 100644 Release/tests/functional/uri/vs14/Uri140_test.vcxproj delete mode 100644 Release/tests/functional/uri/vs14/Uri140_test.vcxproj.filters delete mode 100644 Release/tests/functional/utils/vs14.android/Utils140_test.android.vcxproj delete mode 100644 Release/tests/functional/utils/vs14.android/Utils140_test.android.vcxproj.filters delete mode 100644 Release/tests/functional/utils/vs14.uwp/Utils140_test.uwp.vcxproj delete mode 100644 Release/tests/functional/utils/vs14.uwp/Utils140_test.uwp.vcxproj.filters delete mode 100644 Release/tests/functional/utils/vs14.xp/Utils140_test.xp.vcxproj delete mode 100644 Release/tests/functional/utils/vs14/Utils140_test.vcxproj delete mode 100644 Release/tests/functional/utils/vs14/Utils140_test.vcxproj.filters delete mode 100644 Release/tests/functional/websockets/client/vs14.android/websocketsclient140_test.android.vcxproj delete mode 100644 Release/tests/functional/websockets/client/vs14.uwp/websocketsclient140_test.uwp.vcxproj delete mode 100644 Release/tests/functional/websockets/client/vs14.xp/websocketsclient140_test.xp.vcxproj delete mode 100644 Release/tests/functional/websockets/client/vs14/websocketsclient140_test.vcxproj delete mode 100644 Release/tests/functional/websockets/utilities/vs14.android/packages.config delete mode 100644 Release/tests/functional/websockets/utilities/vs14.android/websockets_test_utilities140.android.vcxproj delete mode 100644 Release/tests/functional/websockets/utilities/vs14.uwp/packages.config delete mode 100644 Release/tests/functional/websockets/utilities/vs14.uwp/websockets_test_utilities140.uwp.vcxproj delete mode 100644 Release/tests/functional/websockets/utilities/vs14.xp/websockets_test_utilities140.xp.vcxproj delete mode 100644 Release/tests/functional/websockets/utilities/vs14/packages.config delete mode 100644 Release/tests/functional/websockets/utilities/vs14/websockets_test_utilities140.vcxproj delete mode 100644 build.root delete mode 100644 cpprestsdk140.sln delete mode 100644 cpprestsdk141.sln diff --git a/Build/Common.Build.Traversal.targets b/Build/Common.Build.Traversal.targets deleted file mode 100644 index db26ed7ada..0000000000 --- a/Build/Common.Build.Traversal.targets +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - - true - - - - - - - - - - - - - - - - diff --git a/Build/Common.Build.settings b/Build/Common.Build.settings deleted file mode 100644 index 16ba09aa54..0000000000 --- a/Build/Common.Build.settings +++ /dev/null @@ -1,242 +0,0 @@ - - - - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - - - Debug - Win32 - - - - - $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), build.root)) - $(BuildRoot)\Build - $(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion@CurrentVersion) - - 140 - 120 - 110 - - $(WindowsSdkDir) - true - true - false - - - - - - $(BuildRoot)\Binaries\$(Platform)\$(Configuration)\ - $(OutputPath) - $(BuildRoot)\Intermediate\$(MSBuildProjectName)\$(Platform)\$(Configuration)\ - $(BuildRoot)\Release\Tests - $(BuildRoot)\Release\src - $(BuildRoot)\Release\Resource - $(BuildRoot)\Release\include - $(BuildRoot)\Release\libs\websocketpp - $(BuildRoot)\packages - $(BuildRoot)\..\Tools\packages - - - - - $(OutDir)\ - - - - $(VS110COMNTOOLS)..\IDE - - - - $(VS120COMNTOOLS)..\IDE - - - - $(TargetsPath)\BinaryDependencies - prompt - 4 - - - false - - - false - $(RunCodeAnalysis) - true - - true - - - true - false - false - true - - - - - Level4 - Use - true - $(EnableCPPAnalysis) - true - /d2notypeopt %(AdditionalOptions) - - - /DTARGET_NAME="$(TARGETNAME)" %(AdditionalOptions) - - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - true - - - - - - _WIN64;_DEBUG;%(PreprocessorDefinitions) - - - true - - - - - - _DEBUG;%(PreprocessorDefinitions) - - - true - - - - - - _WIN64;NDEBUG;%(PreprocessorDefinitions) - - - true - - - - - - NDEBUG;%(PreprocessorDefinitions) - - - true - - - - - - NDEBUG;%(PreprocessorDefinitions) - - - true - - - - - true - full - false - DEBUG;TRACE - x86 - - - - true - full - false - DEBUG;TRACE;X64 - - - - pdbonly - true - TRACE - x86 - - - - pdbonly - true - TRACE;X64 - - - - true - full - false - DEBUG;TRACE;ARM - - - - pdbonly - true - TRACE;ARM - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ResolvedProjectReferencePaths> - Undefined - - - - - - - - <_ResolvedProjectReferencePaths Condition="'%(CopyToOutputDirectory)' != 'Undefined'" - Remove="@(_ResolvedProjectReferencePaths)" /> - - - - - - - diff --git a/Build/Config.Definitions.props b/Build/Config.Definitions.props deleted file mode 100644 index 9eaabbb298..0000000000 --- a/Build/Config.Definitions.props +++ /dev/null @@ -1,29 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - \ No newline at end of file diff --git a/Build/Release.Product.settings b/Build/Release.Product.settings deleted file mode 100644 index 30d0bc9a4f..0000000000 --- a/Build/Release.Product.settings +++ /dev/null @@ -1,64 +0,0 @@ - - - - - true - false - - - - false - true - - - - Unicode - - - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - - false - - $(RunCodeAnalysis) - - - - - - $(CasablancaIncludeDir) - - - - - false - - - Windows - false - true - /SAFESEH%(AdditionalOptions) - - - - - - Disabled - - - - - - NDEBUG;%(PreprocessorDefinitions) - MaxSpeed - true - true - - - - diff --git a/Build/Release.Tests.settings b/Build/Release.Tests.settings deleted file mode 100644 index 2bbff91192..0000000000 --- a/Build/Release.Tests.settings +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - false - - - - - - - $(TestRoot)\Common\utilities\include;$(TestRoot)\Common\UnitTestpp - $(BinariesDirectory)\inc;$(CasablancaIncludeDir) - - - - - - - - diff --git a/Build/version.props b/Build/version.props deleted file mode 100644 index 2b67f6647e..0000000000 --- a/Build/version.props +++ /dev/null @@ -1,11 +0,0 @@ - - - - cpprest - 2 - 10 - 6 - $(CppRestSDKVersionMajor)_$(CppRestSDKVersionMinor) - $(CppRestSDKVersionMajor).$(CppRestSDKVersionMinor) - - diff --git a/NuGet.Config b/NuGet.Config deleted file mode 100644 index abc5b1378c..0000000000 --- a/NuGet.Config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Release/samples/BingRequest/BingRequest140.xp/BingRequest140.xp.vcxproj b/Release/samples/BingRequest/BingRequest140.xp/BingRequest140.xp.vcxproj deleted file mode 100644 index 56afcd81b3..0000000000 --- a/Release/samples/BingRequest/BingRequest140.xp/BingRequest140.xp.vcxproj +++ /dev/null @@ -1,133 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath14) - - - - Application - true - NotSet - v140_xp - - - Application - true - NotSet - v140_xp - - - Application - false - true - NotSet - v140_xp - - - Application - false - true - NotSet - v140_xp - - - - - - - /bigobj %(AdditionalOptions) - NotUsing - Disabled - CPPREST_TARGET_XP;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - Disabled - CPPREST_TARGET_XP;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - MaxSpeed - true - true - CPPREST_TARGET_XP;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - MaxSpeed - true - true - CPPREST_TARGET_XP;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - - - - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9} - - - - \ No newline at end of file diff --git a/Release/samples/BingRequest/BingRequest140.xp/BingRequest140.xp.vcxproj.filters b/Release/samples/BingRequest/BingRequest140.xp/BingRequest140.xp.vcxproj.filters deleted file mode 100644 index cee450afc2..0000000000 --- a/Release/samples/BingRequest/BingRequest140.xp/BingRequest140.xp.vcxproj.filters +++ /dev/null @@ -1,13 +0,0 @@ - - - - - {786631e0-badc-4b3f-bd98-9b13e6a8e5f8} - - - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/BingRequest/BingRequest140/BingRequest140.vcxproj b/Release/samples/BingRequest/BingRequest140/BingRequest140.vcxproj deleted file mode 100644 index bf9a63acc9..0000000000 --- a/Release/samples/BingRequest/BingRequest140/BingRequest140.vcxproj +++ /dev/null @@ -1,141 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - Application - true - NotSet - v140 - - - Application - true - NotSet - v140 - - - Application - false - true - NotSet - v140 - - - Application - false - true - NotSet - v140 - - - - - $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), build.root)) - $(BuildRoot)\Binaries\$(Platform)\$(Configuration)\ - $(OutputPath) - $(BuildRoot)\Release\src - $(BuildRoot)\Release\include - - - - - /bigobj %(AdditionalOptions) - NotUsing - Disabled - WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - Disabled - WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - - - - \ No newline at end of file diff --git a/Release/samples/BingRequest/BingRequest140/BingRequest140.vcxproj.filters b/Release/samples/BingRequest/BingRequest140/BingRequest140.vcxproj.filters deleted file mode 100644 index b78f1994bb..0000000000 --- a/Release/samples/BingRequest/BingRequest140/BingRequest140.vcxproj.filters +++ /dev/null @@ -1,13 +0,0 @@ - - - - - {bc214923-f806-44a3-abd4-08a1aa1a9b3b} - - - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj b/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj deleted file mode 100644 index b5af27cbca..0000000000 --- a/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj +++ /dev/null @@ -1,134 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - 10.0.16299.0 - - - - Application - true - NotSet - v141 - - - Application - true - NotSet - v141 - - - Application - false - true - NotSet - v141 - - - Application - false - true - NotSet - v141 - - - - - - - /bigobj %(AdditionalOptions) - NotUsing - Disabled - WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - Disabled - WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - - - - \ No newline at end of file diff --git a/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj.filters b/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj.filters deleted file mode 100644 index bb6411f159..0000000000 --- a/Release/samples/BingRequest/BingRequest141/BingRequest141.vcxproj.filters +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - Source Files - - - \ 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 1ca303fbdc..9a17d8983d 100644 --- a/Release/samples/BlackJack/BlackJack_Client/BlackJackClient.cpp +++ b/Release/samples/BlackJack/BlackJack_Client/BlackJackClient.cpp @@ -9,7 +9,36 @@ * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ -#include "stdafx.h" +#ifdef _WIN32 +#include + +#include +#include + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#define NOMINMAX +#include +#include +#include + +// ws2tcpip.h - isn't warning clean. +#pragma warning(push) +#pragma warning(disable : 6386) +#include +#pragma warning(pop) + +#include +#endif + +#include +#include +#include +#include + +#include "cpprest/http_client.h" + #include #include #include diff --git a/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client140/BlackJack_Client140.vcxproj b/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client140/BlackJack_Client140.vcxproj deleted file mode 100644 index 6a247f1616..0000000000 --- a/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client140/BlackJack_Client140.vcxproj +++ /dev/null @@ -1,148 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {830b6e2f-9224-41d1-b9c7-a51fc78b00c7} - Win32Proj - BlackJack_Client - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - Application - true - NotSet - v140 - - - Application - true - NotSet - v140 - - - Application - false - true - NotSet - v140 - - - Application - false - true - NotSet - v140 - - - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);..\..\BlackJack_Server;$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);..\..\BlackJack_Server;$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);..\..\BlackJack_Server;$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);..\..\BlackJack_Server;$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - - - - - - Create - Create - Create - Create - - - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client140/BlackJack_Client140.vcxproj.filters b/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client140/BlackJack_Client140.vcxproj.filters deleted file mode 100644 index 127018be70..0000000000 --- a/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client140/BlackJack_Client140.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj b/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj deleted file mode 100644 index 8770125299..0000000000 --- a/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj +++ /dev/null @@ -1,149 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {830b6e2f-9224-41d1-b9c7-a51fc78b00c7} - Win32Proj - BlackJack_Client - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - 10.0.16299.0 - - - - Application - true - NotSet - v141 - - - Application - true - NotSet - v141 - - - Application - false - true - NotSet - v141 - - - Application - false - true - NotSet - v141 - - - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);..\..\BlackJack_Server;$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);..\..\BlackJack_Server;$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);..\..\BlackJack_Server;$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);..\..\BlackJack_Server;$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - - - - - - Create - Create - Create - Create - - - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj.filters b/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj.filters deleted file mode 100644 index d19e3a56d0..0000000000 --- a/Release/samples/BlackJack/BlackJack_Client/BlackJack_Client141/BlackJack_Client141.vcxproj.filters +++ /dev/null @@ -1,30 +0,0 @@ - - - - - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - h;hpp;hxx;hm;inl;inc;xsd - - - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_Client/CMakeLists.txt b/Release/samples/BlackJack/BlackJack_Client/CMakeLists.txt index f884ca8f8d..e5845aa827 100644 --- a/Release/samples/BlackJack/BlackJack_Client/CMakeLists.txt +++ b/Release/samples/BlackJack/BlackJack_Client/CMakeLists.txt @@ -4,7 +4,6 @@ endif() add_executable(blackjackclient BlackJackClient.cpp - stdafx.cpp ) target_link_libraries(blackjackclient cpprest) diff --git a/Release/samples/BlackJack/BlackJack_Client/stdafx.cpp b/Release/samples/BlackJack/BlackJack_Client/stdafx.cpp deleted file mode 100644 index cd389fa0d6..0000000000 --- a/Release/samples/BlackJack/BlackJack_Client/stdafx.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.cpp : source file that includes just the standard includes -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ - -#include "stdafx.h" - -// reference any additional headers you need in STDAFX.H -// and not in this file diff --git a/Release/samples/BlackJack/BlackJack_Client/stdafx.h b/Release/samples/BlackJack/BlackJack_Client/stdafx.h deleted file mode 100644 index 82b776702a..0000000000 --- a/Release/samples/BlackJack/BlackJack_Client/stdafx.h +++ /dev/null @@ -1,44 +0,0 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.h : include file for standard system include files, -* or project specific include files that are used frequently, but -* are changed infrequently -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ - -#pragma once - -#ifdef _WIN32 -#include "targetver.h" - -#include -#include - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#define NOMINMAX -#include -#include -#include - -// ws2tcpip.h - isn't warning clean. -#pragma warning(push) -#pragma warning(disable : 6386) -#include -#pragma warning(pop) - -#include -#endif - -#include -#include -#include -#include - -#include "cpprest/http_client.h" diff --git a/Release/samples/BlackJack/BlackJack_Client/targetver.h b/Release/samples/BlackJack/BlackJack_Client/targetver.h deleted file mode 100644 index 951583c45d..0000000000 --- a/Release/samples/BlackJack/BlackJack_Client/targetver.h +++ /dev/null @@ -1,18 +0,0 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* targetver.h -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ -#pragma once - -// Including SDKDDKVer.h defines the highest available Windows platform. - -// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and -// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. - -#include diff --git a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server140/BlackJack_Server140.vcxproj b/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server140/BlackJack_Server140.vcxproj deleted file mode 100644 index de642bde3c..0000000000 --- a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server140/BlackJack_Server140.vcxproj +++ /dev/null @@ -1,154 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {84350cd1-d406-4a4f-9571-261ca46d77c5} - Win32Proj - BlackJack_Server - SAK - SAK - SAK - $(VCTargetsPath12) - SAK - - - - Application - true - NotSet - v140 - - - Application - true - NotSet - v140 - - - Application - false - true - NotSet - v140 - - - Application - false - true - NotSet - v140 - - - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server140/BlackJack_Server140.vcxproj.filters b/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server140/BlackJack_Server140.vcxproj.filters deleted file mode 100644 index 2de41685ef..0000000000 --- a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server140/BlackJack_Server140.vcxproj.filters +++ /dev/null @@ -1,45 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj b/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj deleted file mode 100644 index ff8468da47..0000000000 --- a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj +++ /dev/null @@ -1,155 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {84350cd1-d406-4a4f-9571-261ca46d77c5} - Win32Proj - BlackJack_Server - SAK - SAK - SAK - $(VCTargetsPath12) - SAK - 10.0.16299.0 - - - - Application - true - NotSet - v141 - - - Application - true - NotSet - v141 - - - Application - false - true - NotSet - v141 - - - Application - false - true - NotSet - v141 - - - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj.filters b/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj.filters deleted file mode 100644 index a13f88916c..0000000000 --- a/Release/samples/BlackJack/BlackJack_Server/BlackJack_Server141/BlackJack_Server141.vcxproj.filters +++ /dev/null @@ -1,42 +0,0 @@ - - - - - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - h;hpp;hxx;hm;inl;inc;xsd - - - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/BlackJack/BlackJack_Server/CMakeLists.txt b/Release/samples/BlackJack/BlackJack_Server/CMakeLists.txt index c5b2fec0af..8073412fc1 100644 --- a/Release/samples/BlackJack/BlackJack_Server/CMakeLists.txt +++ b/Release/samples/BlackJack/BlackJack_Server/CMakeLists.txt @@ -5,8 +5,18 @@ endif() add_executable(blackjackserver BlackJack_Server.cpp Dealer.cpp - stdafx.cpp Table.cpp ) target_link_libraries(blackjackserver cpprest) + +if(MSVC) + get_target_property(_srcs blackjackserver SOURCES) + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") + set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/blackjack-server-stdafx.pch") + set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/blackjack-server-stdafx.pch") + endif() + set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h /Fpblackjack-server-stdafx.pch") + target_sources(blackjackserver PRIVATE stdafx.cpp) + target_compile_options(blackjackserver PRIVATE /Yustdafx.h /Fpblackjack-server-stdafx.pch) +endif() diff --git a/Release/samples/Oauth1Client/CMakeLists.txt b/Release/samples/Oauth1Client/CMakeLists.txt index 4630cba8fe..e77d3fdeaa 100644 --- a/Release/samples/Oauth1Client/CMakeLists.txt +++ b/Release/samples/Oauth1Client/CMakeLists.txt @@ -1,8 +1,7 @@ if (NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) add_executable(oauth1client Oauth1Client.cpp - stdafx.cpp ) - + target_link_libraries(oauth1client cpprest) -endif() \ No newline at end of file +endif() diff --git a/Release/samples/Oauth1Client/Oauth1Client.cpp b/Release/samples/Oauth1Client/Oauth1Client.cpp index d360d37d54..8c27ef2f4e 100644 --- a/Release/samples/Oauth1Client/Oauth1Client.cpp +++ b/Release/samples/Oauth1Client/Oauth1Client.cpp @@ -26,7 +26,8 @@ Set following entry in the hosts file: 127.0.0.1 testhost.local */ -#include "stdafx.h" +#include +#include "cpprest/http_client.h" #if defined(_WIN32) && !defined(__cplusplus_winrt) // Extra includes for Windows desktop. @@ -301,4 +302,3 @@ int main(int argc, char *argv[]) ucout << "Done." << std::endl; return 0; } - diff --git a/Release/samples/Oauth1Client/Oauth1Client140/Oauth1Client140.vcxproj b/Release/samples/Oauth1Client/Oauth1Client140/Oauth1Client140.vcxproj deleted file mode 100644 index 2d9d51c16d..0000000000 --- a/Release/samples/Oauth1Client/Oauth1Client140/Oauth1Client140.vcxproj +++ /dev/null @@ -1,205 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {850CCB95-CFA8-4E41-9D1D-387C0C186740} - Win32Proj - Oauth1Client - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - Application - true - NotSet - v140 - - - Application - true - NotSet - v140 - - - Application - true - NotSet - v140 - - - Application - false - true - NotSet - v140 - - - Application - false - true - NotSet - v140 - - - Application - false - true - NotSet - v140 - - - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - \ No newline at end of file diff --git a/Release/samples/Oauth1Client/Oauth1Client140/Oauth1Client140.vcxproj.filters b/Release/samples/Oauth1Client/Oauth1Client140/Oauth1Client140.vcxproj.filters deleted file mode 100644 index 48d2ebae5f..0000000000 --- a/Release/samples/Oauth1Client/Oauth1Client140/Oauth1Client140.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj b/Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj deleted file mode 100644 index 6ff9eeb18a..0000000000 --- a/Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj +++ /dev/null @@ -1,206 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {850CCB95-CFA8-4E41-9D1D-387C0C186740} - Win32Proj - Oauth1Client - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - 10.0.16299.0 - - - - Application - true - NotSet - v141 - - - Application - true - NotSet - v141 - - - Application - true - NotSet - v141 - - - Application - false - true - NotSet - v141 - - - Application - false - true - NotSet - v141 - - - Application - false - true - NotSet - v141 - - - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - \ No newline at end of file diff --git a/Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj.filters b/Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj.filters deleted file mode 100644 index 48d2ebae5f..0000000000 --- a/Release/samples/Oauth1Client/Oauth1Client141/Oauth1Client141.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/Oauth1Client/stdafx.cpp b/Release/samples/Oauth1Client/stdafx.cpp deleted file mode 100644 index cd389fa0d6..0000000000 --- a/Release/samples/Oauth1Client/stdafx.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.cpp : source file that includes just the standard includes -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ - -#include "stdafx.h" - -// reference any additional headers you need in STDAFX.H -// and not in this file diff --git a/Release/samples/Oauth1Client/stdafx.h b/Release/samples/Oauth1Client/stdafx.h deleted file mode 100644 index 88797e88c3..0000000000 --- a/Release/samples/Oauth1Client/stdafx.h +++ /dev/null @@ -1,17 +0,0 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.h : include file for standard system include files, -* or project specific include files that are used frequently, but -* are changed infrequently -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ - -#pragma once - -#include -#include "cpprest/http_client.h" diff --git a/Release/samples/Oauth2Client/CMakeLists.txt b/Release/samples/Oauth2Client/CMakeLists.txt index 8c3bdbc118..4da12bb474 100644 --- a/Release/samples/Oauth2Client/CMakeLists.txt +++ b/Release/samples/Oauth2Client/CMakeLists.txt @@ -1,8 +1,7 @@ if (NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) add_executable(oauth2client Oauth2Client.cpp - stdafx.cpp ) target_link_libraries(oauth2client cpprest) -endif() \ No newline at end of file +endif() diff --git a/Release/samples/Oauth2Client/Oauth2Client.cpp b/Release/samples/Oauth2Client/Oauth2Client.cpp index 59a963eaff..8d62b89cda 100644 --- a/Release/samples/Oauth2Client/Oauth2Client.cpp +++ b/Release/samples/Oauth2Client/Oauth2Client.cpp @@ -26,7 +26,8 @@ Set following entry in the hosts file: 127.0.0.1 testhost.local */ -#include "stdafx.h" +#include +#include "cpprest/http_client.h" #if defined(_WIN32) && !defined(__cplusplus_winrt) // Extra includes for Windows desktop. @@ -321,4 +322,3 @@ int main(int argc, char *argv[]) ucout << "Done." << std::endl; return 0; } - diff --git a/Release/samples/Oauth2Client/Oauth2Client140/Oauth2Client140.vcxproj b/Release/samples/Oauth2Client/Oauth2Client140/Oauth2Client140.vcxproj deleted file mode 100644 index 5b69ac56a5..0000000000 --- a/Release/samples/Oauth2Client/Oauth2Client140/Oauth2Client140.vcxproj +++ /dev/null @@ -1,205 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654} - Win32Proj - Oauth2Client - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - Application - true - NotSet - v140 - - - Application - true - NotSet - v140 - - - Application - true - NotSet - v140 - - - Application - false - true - NotSet - v140 - - - Application - false - true - NotSet - v140 - - - Application - false - true - NotSet - v140 - - - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - \ No newline at end of file diff --git a/Release/samples/Oauth2Client/Oauth2Client140/Oauth2Client140.vcxproj.filters b/Release/samples/Oauth2Client/Oauth2Client140/Oauth2Client140.vcxproj.filters deleted file mode 100644 index d11e5aec8b..0000000000 --- a/Release/samples/Oauth2Client/Oauth2Client140/Oauth2Client140.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj b/Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj deleted file mode 100644 index 1ff3cc807d..0000000000 --- a/Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj +++ /dev/null @@ -1,206 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654} - Win32Proj - Oauth2Client - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - 10.0.16299.0 - - - - Application - true - NotSet - v141 - - - Application - true - NotSet - v141 - - - Application - true - NotSet - v141 - - - Application - false - true - NotSet - v141 - - - Application - false - true - NotSet - v141 - - - Application - false - true - NotSet - v141 - - - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - -Zm140 %(AdditionalOptions) - - - Console - true - true - true - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - \ No newline at end of file diff --git a/Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj.filters b/Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj.filters deleted file mode 100644 index d11e5aec8b..0000000000 --- a/Release/samples/Oauth2Client/Oauth2Client141/Oauth2Client141.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/Oauth2Client/stdafx.cpp b/Release/samples/Oauth2Client/stdafx.cpp deleted file mode 100644 index cd389fa0d6..0000000000 --- a/Release/samples/Oauth2Client/stdafx.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.cpp : source file that includes just the standard includes -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ - -#include "stdafx.h" - -// reference any additional headers you need in STDAFX.H -// and not in this file diff --git a/Release/samples/Oauth2Client/stdafx.h b/Release/samples/Oauth2Client/stdafx.h deleted file mode 100644 index 88797e88c3..0000000000 --- a/Release/samples/Oauth2Client/stdafx.h +++ /dev/null @@ -1,17 +0,0 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.h : include file for standard system include files, -* or project specific include files that are used frequently, but -* are changed infrequently -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ - -#pragma once - -#include -#include "cpprest/http_client.h" diff --git a/Release/samples/SearchFile/SearchFile140/SearchFile140.vcxproj b/Release/samples/SearchFile/SearchFile140/SearchFile140.vcxproj deleted file mode 100644 index c749d29e9c..0000000000 --- a/Release/samples/SearchFile/SearchFile140/SearchFile140.vcxproj +++ /dev/null @@ -1,146 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {F03BEE03-BEFB-4B17-A774-D9C8246530D4} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - Application - true - NotSet - v140 - - - Application - true - NotSet - v140 - - - Application - true - NotSet - v140 - - - Application - false - true - NotSet - v140 - - - Application - false - true - NotSet - v140 - - - Application - false - true - NotSet - v140 - - - - - - - /bigobj %(AdditionalOptions) - NotUsing - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - - - - \ No newline at end of file diff --git a/Release/samples/SearchFile/SearchFile140/SearchFile140.vcxproj.filters b/Release/samples/SearchFile/SearchFile140/SearchFile140.vcxproj.filters deleted file mode 100644 index 2794140178..0000000000 --- a/Release/samples/SearchFile/SearchFile140/SearchFile140.vcxproj.filters +++ /dev/null @@ -1,13 +0,0 @@ - - - - - {bc214923-f806-44a3-abd4-08a1aa1a9b3b} - - - - - Source Files - - - \ No newline at end of file diff --git a/Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj b/Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj deleted file mode 100644 index 4c1d729dcd..0000000000 --- a/Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj +++ /dev/null @@ -1,147 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {F03BEE03-BEFB-4B17-A774-D9C8246530D4} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - 10.0.16299.0 - - - - Application - true - NotSet - v141 - - - Application - true - NotSet - v141 - - - Application - true - NotSet - v141 - - - Application - false - true - NotSet - v141 - - - Application - false - true - NotSet - v141 - - - Application - false - true - NotSet - v141 - - - - - - - /bigobj %(AdditionalOptions) - NotUsing - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - /bigobj %(AdditionalOptions) - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(CasablancaIncludeDir) - Async - - - Console - true - true - true - - - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - - - - \ No newline at end of file diff --git a/Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj.filters b/Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj.filters deleted file mode 100644 index 2794140178..0000000000 --- a/Release/samples/SearchFile/SearchFile141/SearchFile141.vcxproj.filters +++ /dev/null @@ -1,13 +0,0 @@ - - - - - {bc214923-f806-44a3-abd4-08a1aa1a9b3b} - - - - - Source Files - - - \ No newline at end of file diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index bb3065e607..eceaad7437 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -180,7 +180,7 @@ if(MSVC) set_source_files_properties(pch/stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h") target_sources(cpprest PRIVATE pch/stdafx.cpp) - target_compile_options(cpprest PRIVATE /Yustdafx.h /Zm200) + target_compile_options(cpprest PRIVATE /Yustdafx.h) endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") diff --git a/Release/src/build/android.vcxitems b/Release/src/build/android.vcxitems deleted file mode 100644 index eaf19e2057..0000000000 --- a/Release/src/build/android.vcxitems +++ /dev/null @@ -1,31 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 248F659F-DAC5-46E8-AC09-60EC9FC95053 - true - 6a3ec03a-67b9-4430-9eb3-a56acc7d127e - {65951c40-a332-4b54-89c2-7cdaf30d5f66} - android - - - - %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/src/build/android.vcxitems.filters b/Release/src/build/android.vcxitems.filters deleted file mode 100644 index 819746782d..0000000000 --- a/Release/src/build/android.vcxitems.filters +++ /dev/null @@ -1,39 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - {8660c551-ea8d-4dda-86b8-4a74cfa9a271} - - - {5489914b-c16a-429b-b787-2d4621924a1c} - - - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/Release/src/build/common.vcxitems b/Release/src/build/common.vcxitems deleted file mode 100644 index 520e0dbac3..0000000000 --- a/Release/src/build/common.vcxitems +++ /dev/null @@ -1,93 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 248F659F-DAC5-46E8-AC09-60EC9FC95053 - true - b19fa703-0bf0-4e1f-8927-b0eaeb6aa823 - {594dcb5f-07e3-4084-a2ce-268611fa629f} - common - common - - - - %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) - - - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/src/build/common.vcxitems.filters b/Release/src/build/common.vcxitems.filters deleted file mode 100644 index 5445979e22..0000000000 --- a/Release/src/build/common.vcxitems.filters +++ /dev/null @@ -1,227 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - {3bdf9ddb-6199-4b83-84cd-e8617e78294e} - - - {42f86193-fcdc-443d-8ede-8fd31abe6643} - - - {ed89d519-15d6-47d9-90cb-e6c25bcaa323} - - - {e5ecd256-178a-403a-9249-5d15463ad051} - - - {d32b3879-7333-4ab4-8ef2-dd72aed7b5dc} - - - {1c12997c-5bf5-4b60-853e-a5f9c8303760} - - - {97da7aee-41c8-4948-bb0e-c31cec1bfb16} - - - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\pch - - - Header Files\pplx - - - Header Files\pplx - - - Header Files\pplx - - - Header Files\pplx - - - Header Files\pplx - - - Header Files\cpprest\details - - - Header Files\cpprest\details - - - Header Files\cpprest - - - Header Files\cpprest\details - - - Header Files\private - - - Header Files\private - - - Header Files\private - - - Header Files\private - - - - - Header Files\cpprest\details - - - \ No newline at end of file diff --git a/Release/src/build/cpprest.natvis b/Release/src/build/cpprest.natvis deleted file mode 100644 index 621c147881..0000000000 --- a/Release/src/build/cpprest.natvis +++ /dev/null @@ -1,207 +0,0 @@ - - - - - - m_scheme - m_host - m_port - m_user_info - m_path - m_query - m_fragment - - - - - {m_uri} - - m_components - - - - - - m_uri - - - - - {m_username} - - m_username - - - - - {"default"} - {"disabled"} - {"auto discovery"} - {m_address} - - "default" - "disabled" - "auto discovery" - m_address - m_credentials - - - - - - m_proxy - m_credentials - m_timeout._MyRep - m_guarantee_order - m_chunksize - - - - - {_base_uri} - - - - {m_uri} - - - - [{_m_impl._Ptr->m_method}] - - _m_impl._Ptr->m_method - _m_impl._Ptr->m_uri - ((*((web::http::details::http_msg_base*)(&(*((web::http::details::_http_request*)((_m_impl)._Ptr)))))).m_headers).m_headers - - - - - [{_m_impl._Ptr->m_status_code}, {_m_impl._Ptr->m_reason_phrase}] - - _m_impl._Ptr->m_status_code - _m_impl._Ptr->m_reason_phrase - ((*((web::http::details::http_msg_base*)(&(*((web::http::details::_http_request*)((_m_impl)._Ptr)))))).m_headers).m_headers - - - - - - m_proxy - m_credentials - m_headers - - - - - {m_client._Ptr->m_callback_client._Ptr->m_uri} - - m_client._Ptr->m_callback_client._Ptr->m_uri - m_client._Ptr->m_callback_client._Ptr->m_config - - - - - {m_client._Ptr->m_uri} - - m_client._Ptr->m_uri - m_client._Ptr->m_config - - - - - - text" - "binary" - "close" - "ping" - "pong" - m_length - m_body - - - - - - "text" - "binary" - "close" - "ping" - "pong" - m_body - - - - - - {m_intval} - - - - {m_uintval} - - - - {m_value} - - - - - {{size = {m_elements._Mylast - m_elements._Myfirst}}} - - - m_elements._Mylast - m_elements._Myfirst - m_elements._Myfirst - - - - - - {{size = {m_elements._Mylast - m_elements._Myfirst}}} - - - m_elements._Mylast - m_elements._Myfirst - m_elements._Myfirst - - - - - - - {(*((web::json::details::_Number*)((m_value)._Myptr))).m_number} - - - - {(*((web::json::details::_Boolean*)(m_value._Myptr))).m_value} - - - - {((((&((*((web::json::details::_String*)(m_value._Myptr))).m_string)))))} - - - null - - not initialized - not initialized - - - object {(*((web::json::details::_Object*)(m_value._Myptr))).m_object} - - - - array {(*((web::json::details::_Array*)(m_value._Myptr))).m_array} - - - - - (*((web::json::details::_Object*)(m_value._Myptr))).m_object.m_elements._Mylast - (*((web::json::details::_Object*)(m_value._Myptr))).m_object.m_elements._Myfirst - (*((web::json::details::_Object*)(m_value._Myptr))).m_object.m_elements._Myfirst - - - - (*((web::json::details::_Array*)(m_value._Myptr))).m_array.m_elements._Mylast - (*((web::json::details::_Array*)(m_value._Myptr))).m_array.m_elements._Myfirst - (*((web::json::details::_Array*)(m_value._Myptr))).m_array.m_elements._Myfirst - - - - - - \ No newline at end of file diff --git a/Release/src/build/init.ps1 b/Release/src/build/init.ps1 deleted file mode 100644 index 595baeaaa9..0000000000 --- a/Release/src/build/init.ps1 +++ /dev/null @@ -1,23 +0,0 @@ -param($installPath, $toolsPath, $package) - -function Copy-Natvis($DestFolder) -{ - if ((Test-Path $DestFolder) -eq $True) - { - # Update casablanca version for each release here. - $DestFile = Join-Path -path $DestFolder -childpath "cpprest2_10.natvis"; - - # Check to see if cpp rest natvis file for this version already exists - # if not, then copy into user profile for Visual Studio to pick up - if ((Test-Path $DestFile) -eq $False) - { - $SrcFile = Join-Path -path $toolsPath -childpath "cpprest.natvis"; - Copy-Item $SrcFile $DestFile; - } - } -} - -$VS2013Folder = Join-Path -path $env:userprofile -childpath "Documents\Visual Studio 2013\Visualizers"; -$VS2015Folder = Join-Path -path $env:userprofile -childpath "Documents\Visual Studio 2015\Visualizers"; -Copy-Natvis $VS2013Folder; -Copy-Natvis $VS2015Folder; \ No newline at end of file diff --git a/Release/src/build/other.vcxitems b/Release/src/build/other.vcxitems deleted file mode 100644 index 2199600b11..0000000000 --- a/Release/src/build/other.vcxitems +++ /dev/null @@ -1,22 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 248F659F-DAC5-46E8-AC09-60EC9FC95053 - true - 388fd5af-5c41-4452-97f0-2841cee780b6 - {3d5908f7-7673-4229-bc46-2007a7af9cae} - other - - - - %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) - - - - - - - - - \ No newline at end of file diff --git a/Release/src/build/other.vcxitems.filters b/Release/src/build/other.vcxitems.filters deleted file mode 100644 index caa96f0b2a..0000000000 --- a/Release/src/build/other.vcxitems.filters +++ /dev/null @@ -1,16 +0,0 @@ - - - - - {627bd7c9-4277-424f-b76c-849f88aa536a} - - - {efbed7e8-e66d-48e1-97f5-d687726e1748} - - - - - Source Files - - - \ No newline at end of file diff --git a/Release/src/build/vs14.android/casablanca140.android.vcxproj b/Release/src/build/vs14.android/casablanca140.android.vcxproj deleted file mode 100644 index 038f56b125..0000000000 --- a/Release/src/build/vs14.android/casablanca140.android.vcxproj +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - Debug - ARM - - - Debug - x86 - - - Release - ARM - - - Release - x86 - - - - - - - {AFB49019-965B-4C10-BAFF-C86C16D58010} - Android - Android - 2.0 - cpprestsdk140.android - - - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - - - - - true - - - true - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Enabled - c++11 - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - d - - - $(CppRestBaseFileName)140$(DebugFileSuffix)_android_$(CppRestSDKVersionFileSuffix) - - - true - - - true - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - diff --git a/Release/src/build/vs14.android/packages.config b/Release/src/build/vs14.android/packages.config deleted file mode 100644 index 746b7f61a2..0000000000 --- a/Release/src/build/vs14.android/packages.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/Release/src/build/vs14.static/casablanca140.static.vcxproj b/Release/src/build/vs14.static/casablanca140.static.vcxproj deleted file mode 100644 index cda12db6a7..0000000000 --- a/Release/src/build/vs14.static/casablanca140.static.vcxproj +++ /dev/null @@ -1,84 +0,0 @@ - - - - - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A} - Win32Proj - SAK - SAK - SAK - SAK - StaticLibrary - v140 - false - false - cpprestsdk140.static - 8.1 - - - - - - - - - - - - - - - - - - - d - - - lib$(CppRestBaseFileName)140$(DebugFileSuffix)_$(CppRestSDKVersionFileSuffix) - - - - Designer - - - - - _NO_ASYNCRTIMP;_ASYNCRT_EXPORT;_PPLX_EXPORT;WIN32;_MBCS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Use - stdafx.h - -Zm300 /bigobj %(AdditionalOptions) - MultiThreadedDebugDLL - MultiThreadedDLL - true - - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - false - false - false - false - false - false - - - Winhttp.lib;httpapi.lib;bcrypt.lib;crypt32.lib;%(AdditionalDependencies) - UseLinkTimeCodeGeneration - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file diff --git a/Release/src/build/vs14.static/packages.config b/Release/src/build/vs14.static/packages.config deleted file mode 100644 index 21a51fdf83..0000000000 --- a/Release/src/build/vs14.static/packages.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/Release/src/build/vs14.uwp/cpprestsdk140.uwp.staticlib.vcxproj b/Release/src/build/vs14.uwp/cpprestsdk140.uwp.staticlib.vcxproj deleted file mode 100644 index 2918824b65..0000000000 --- a/Release/src/build/vs14.uwp/cpprestsdk140.uwp.staticlib.vcxproj +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {47A5CFDC-C244-45A6-9830-38CB303CB495} - StaticLibrary - en-US - 14.0 - true - Windows Store - 8.2 - cpprestsdk140.uwp.staticlib - v140 - StaticLibrary - $(OutDir)\$(MsBuildProjectName) - 10.0.10240.0 - 10.0.10240.0 - - - - - - - - - - - - - - - - d - - - lib$(CppRestBaseFileName)140$(DebugFileSuffix)_uwp_$(CppRestSDKVersionFileSuffix) - - - - - false - false - - - - _NO_ASYNCRTIMP;_NO_PPLXIMP;_USRDLL;%(PreprocessorDefinitions); - Use - true - $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;%(AdditionalIncludeDirectories) - Use - stdafx.h - -Zm250 /bigobj %(AdditionalOptions) - true - - - Console - false - UseLinkTimeCodeGeneration - false - - - - - - copy /Y $(OutDir)\* $(OutDir)..\ - exit 0 - Copying $(TargetName).winrt binaries to OutDir and removing appcontainer flag - - - MachineX86 - - - MachineX86 - - - MachineX64 - - - MachineX64 - - - - - \ No newline at end of file diff --git a/Release/src/build/vs14.uwp/cpprestsdk140.uwp.vcxproj b/Release/src/build/vs14.uwp/cpprestsdk140.uwp.vcxproj deleted file mode 100644 index 88a336088c..0000000000 --- a/Release/src/build/vs14.uwp/cpprestsdk140.uwp.vcxproj +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} - DynamicLibrary - en-US - 14.0 - true - Windows Store - 10.0.10240.0 - 10.0.10240.0 - 10.0 - cpprestsdk140.uwp - v140 - DynamicLibrary - $(OutDir)\$(MsBuildProjectName) - - - - - - - - - - - - - - - - d - - - $(CppRestBaseFileName)140$(DebugFileSuffix)_uwp_$(CppRestSDKVersionFileSuffix) - - - - - false - false - - - - _ASYNCRT_EXPORT;_PPLX_EXPORT;_USRDLL;%(PreprocessorDefinitions); - Use - true - $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;%(AdditionalIncludeDirectories) - Use - stdafx.h - -Zm250 /bigobj %(AdditionalOptions) - true - - - Console - false - UseLinkTimeCodeGeneration - false - - - - - - copy /Y "$(OutDir)\*" "$(OutDir)..\" - link /edit /appcontainer:no "$(OutDir)..\$(TargetName).dll" - exit 0 - Copying $(TargetName).winrt binaries to OutDir and removing appcontainer flag - - - - - \ No newline at end of file diff --git a/Release/src/build/vs14.xp/casablanca140.xp.vcxproj b/Release/src/build/vs14.xp/casablanca140.xp.vcxproj deleted file mode 100644 index 7f3e81937a..0000000000 --- a/Release/src/build/vs14.xp/casablanca140.xp.vcxproj +++ /dev/null @@ -1,86 +0,0 @@ - - - - - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9} - Win32Proj - SAK - SAK - SAK - SAK - DynamicLibrary - v140_xp - false - true - cpprestsdk140.xp - 8.1 - - - - - - - - true - true - true - true - - - - - - - - - - - - - - - d - - - $(CppRestBaseFileName)140$(DebugFileSuffix)_xp_$(CppRestSDKVersionFileSuffix) - - - - Designer - - - - - CPPREST_TARGET_XP;_ASYNCRT_EXPORT;_PPLX_EXPORT;WIN32;_MBCS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Use - stdafx.h - -Zm300 /bigobj %(AdditionalOptions) - MultiThreadedDebugDLL - MultiThreadedDLL - true - - - 4503;4592;%(DisableSpecificWarnings) - 4503;4592;%(DisableSpecificWarnings) - 4503;4592;%(DisableSpecificWarnings) - 4503;4592;%(DisableSpecificWarnings) - 4503;4592;%(DisableSpecificWarnings) - 4503;4592;%(DisableSpecificWarnings) - - - Winhttp.lib;crypt32.lib;%(AdditionalDependencies) - UseLinkTimeCodeGeneration - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file diff --git a/Release/src/build/vs14.xp/packages.config b/Release/src/build/vs14.xp/packages.config deleted file mode 100644 index 21a51fdf83..0000000000 --- a/Release/src/build/vs14.xp/packages.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/Release/src/build/vs14/casablanca140.vcxproj b/Release/src/build/vs14/casablanca140.vcxproj deleted file mode 100644 index cca6328ef9..0000000000 --- a/Release/src/build/vs14/casablanca140.vcxproj +++ /dev/null @@ -1,78 +0,0 @@ - - - - - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} - Win32Proj - SAK - SAK - SAK - SAK - DynamicLibrary - v140 - false - false - cpprestsdk140 - - - - - - - - - - - - - - - - - - - d - - - $(CppRestBaseFileName)140$(DebugFileSuffix)_$(CppRestSDKVersionFileSuffix) - - - - Designer - - - - - _ASYNCRT_EXPORT;_PPLX_EXPORT;WIN32;_MBCS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Use - stdafx.h - -Zm300 /bigobj %(AdditionalOptions) - MultiThreadedDebugDLL - MultiThreadedDLL - true - - - 4503;4592;%(DisableSpecificWarnings) - 4503;4592;%(DisableSpecificWarnings) - 4503;4592;%(DisableSpecificWarnings) - 4503;4592;%(DisableSpecificWarnings) - 4503;4592;%(DisableSpecificWarnings) - 4503;4592;%(DisableSpecificWarnings) - - - Winhttp.lib;httpapi.lib;bcrypt.lib;crypt32.lib;%(AdditionalDependencies) - UseLinkTimeCodeGeneration - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file diff --git a/Release/src/build/vs14/packages.config b/Release/src/build/vs14/packages.config deleted file mode 100644 index 21a51fdf83..0000000000 --- a/Release/src/build/vs14/packages.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/Release/src/build/vs141.android/cpprest141.android.vcxproj b/Release/src/build/vs141.android/cpprest141.android.vcxproj deleted file mode 100644 index 99a265fa01..0000000000 --- a/Release/src/build/vs141.android/cpprest141.android.vcxproj +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - Debug - ARM - - - Debug - x86 - - - Release - ARM - - - Release - x86 - - - - - - - {AFB49019-965B-4C10-BAFF-C86C16D58010} - Android - Android - 3.0 - cpprest141.android - 15.0 - - - - - StaticLibrary - true - Clang_3_8 - gnustl_static - android-24 - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - - - - - true - - - true - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(CasablancaSrcDir)\android;$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Enabled - c++11 - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(CasablancaSrcDir)\android;$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(CasablancaSrcDir)\android;$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(CasablancaSrcDir)\android;$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - d - - - $(CppRestBaseFileName)141$(DebugFileSuffix)_android_$(CppRestSDKVersionFileSuffix) - - - true - - - true - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file diff --git a/Release/src/build/vs141.android/packages.config b/Release/src/build/vs141.android/packages.config deleted file mode 100644 index 746b7f61a2..0000000000 --- a/Release/src/build/vs141.android/packages.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/Release/src/build/vs141.uwp/cpprest141.uwp.vcxproj b/Release/src/build/vs141.uwp/cpprest141.uwp.vcxproj deleted file mode 100644 index f0ee5aae9d..0000000000 --- a/Release/src/build/vs141.uwp/cpprest141.uwp.vcxproj +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} - DynamicLibrary - en-US - 14.0 - true - Windows Store - 10.0.16299.0 - 10.0.16299.0 - 10.0 - cpprest141.uwp - v141 - DynamicLibrary - $(OutDir)\$(MsBuildProjectName) - - - - - - - - - - - - - - - - d - - - $(CppRestBaseFileName)141$(DebugFileSuffix)_uwp_$(CppRestSDKVersionFileSuffix) - - - - - false - false - - - - _ASYNCRT_EXPORT;_PPLX_EXPORT;_USRDLL;%(PreprocessorDefinitions); - Use - true - $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;%(AdditionalIncludeDirectories) - Use - stdafx.h - -Zm250 /bigobj %(AdditionalOptions) - true - - - Console - false - UseLinkTimeCodeGeneration - false - - - - - - \ No newline at end of file diff --git a/Release/src/build/vs141/cpprest141.vcxproj b/Release/src/build/vs141/cpprest141.vcxproj deleted file mode 100644 index 794a5155ba..0000000000 --- a/Release/src/build/vs141/cpprest141.vcxproj +++ /dev/null @@ -1,85 +0,0 @@ - - - - - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} - Win32Proj - SAK - SAK - SAK - SAK - DynamicLibrary - v141 - false - false - cpprest141 - 10.0.16299.0 - - - true - true - true - true - - - - - - - - - - - - - - - - - - - d - - - $(CppRestBaseFileName)141$(DebugFileSuffix)_$(CppRestSDKVersionFileSuffix) - - - - Designer - - - - - _ASYNCRT_EXPORT;_PPLX_EXPORT;WIN32;_MBCS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Use - stdafx.h - -Zm300 /bigobj %(AdditionalOptions) - MultiThreadedDebugDLL - MultiThreadedDLL - true - - - 4503;4592;%(DisableSpecificWarnings) - 4503;4592;%(DisableSpecificWarnings) - 4503;4592;%(DisableSpecificWarnings) - 4503;4592;%(DisableSpecificWarnings) - 4503;4592;%(DisableSpecificWarnings) - 4503;4592;%(DisableSpecificWarnings) - - - Winhttp.lib;httpapi.lib;bcrypt.lib;crypt32.lib;%(AdditionalDependencies) - UseLinkTimeCodeGeneration - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file diff --git a/Release/src/build/vs141/packages.config b/Release/src/build/vs141/packages.config deleted file mode 100644 index 21a51fdf83..0000000000 --- a/Release/src/build/vs141/packages.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/Release/src/build/win32.vcxitems b/Release/src/build/win32.vcxitems deleted file mode 100644 index 216b00fca5..0000000000 --- a/Release/src/build/win32.vcxitems +++ /dev/null @@ -1,33 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 248F659F-DAC5-46E8-AC09-60EC9FC95053 - true - c9564eb9-0f37-49cc-a2d6-b1a42b8bfb10 - {f40f4804-50f9-4257-8d74-b9cbb19ac4c3} - win32 - - - - %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/src/build/win32.vcxitems.filters b/Release/src/build/win32.vcxitems.filters deleted file mode 100644 index 0a8e8e865a..0000000000 --- a/Release/src/build/win32.vcxitems.filters +++ /dev/null @@ -1,39 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - {48e3e0ed-8995-4e0b-b58c-a9c38bac54de} - - - {95470a15-70ac-4e0f-ae3b-e5721e93400c} - - - - - Header Files - - - Header Files - - - - - - \ No newline at end of file diff --git a/Release/src/build/winrt.vcxitems b/Release/src/build/winrt.vcxitems deleted file mode 100644 index c07ce03c97..0000000000 --- a/Release/src/build/winrt.vcxitems +++ /dev/null @@ -1,31 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - 248F659F-DAC5-46E8-AC09-60EC9FC95053 - true - 6b93d548-6644-4909-8c97-3e19aac98514 - {0a9ba181-7876-4b3d-a5e0-ee673fa51c05} - winrt - - - - %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/src/build/winrt.vcxitems.filters b/Release/src/build/winrt.vcxitems.filters deleted file mode 100644 index 746985781b..0000000000 --- a/Release/src/build/winrt.vcxitems.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - {1a4ff9ed-f148-42a8-8119-185e2c58800e} - - - {5e8ffeb7-9f5b-45ae-baa1-45d4634d7dc4} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - - - - \ No newline at end of file diff --git a/Release/tests/common/TestRunner/ios/ios_runner.xcodeproj/project.pbxproj b/Release/tests/common/TestRunner/ios/ios_runner.xcodeproj/project.pbxproj deleted file mode 100644 index 4fa4952084..0000000000 --- a/Release/tests/common/TestRunner/ios/ios_runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,368 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - D5E513901A1BEA1D0060F252 /* ios_runnerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = D5E5138F1A1BEA1D0060F252 /* ios_runnerTests.mm */; }; - D5E5139A1A1BFDD80060F252 /* libunittestpp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D5E513991A1BFDD80060F252 /* libunittestpp.a */; }; - D5E5139C1A1BFECD0060F252 /* libcpprest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D5E5139B1A1BFECD0060F252 /* libcpprest.a */; }; - D5E513A61A1BFEE20060F252 /* libcommon_utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D5E5139D1A1BFEE20060F252 /* libcommon_utilities.a */; }; - D5E513A71A1BFEE20060F252 /* libhttpclient_test.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D5E5139E1A1BFEE20060F252 /* libhttpclient_test.a */; }; - D5E513A81A1BFEE20060F252 /* libhttplistener_test.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D5E5139F1A1BFEE20060F252 /* libhttplistener_test.a */; }; - D5E513A91A1BFEE20060F252 /* libhttptest_utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D5E513A01A1BFEE20060F252 /* libhttptest_utilities.a */; }; - D5E513AA1A1BFEE20060F252 /* libjson_test.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D5E513A11A1BFEE20060F252 /* libjson_test.a */; }; - D5E513AB1A1BFEE20060F252 /* libpplx_test.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D5E513A21A1BFEE20060F252 /* libpplx_test.a */; }; - D5E513AC1A1BFEE20060F252 /* libstreams_test.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D5E513A31A1BFEE20060F252 /* libstreams_test.a */; }; - D5E513AD1A1BFEE20060F252 /* liburi_test.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D5E513A41A1BFEE20060F252 /* liburi_test.a */; }; - D5E513AE1A1BFEE20060F252 /* libutils_test.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D5E513A51A1BFEE20060F252 /* libutils_test.a */; }; - D5E513B01A1C01820060F252 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D5E513AF1A1C01820060F252 /* libiconv.dylib */; }; - D5E513B41A1C02210060F252 /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D5E513B21A1C02200060F252 /* libcrypto.a */; }; - D5E513B51A1C02210060F252 /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D5E513B31A1C02210060F252 /* libssl.a */; }; - D5E513B71A1C02570060F252 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5E513B61A1C02570060F252 /* Security.framework */; }; - D5E513B81A1C02CF0060F252 /* boost.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5E513B11A1C01D30060F252 /* boost.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - D52BABA91A1C064100FAE04C /* libwebsocketclient_test.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libwebsocketclient_test.a; path = ../../../../../Build_iOS/build.debug/build.i386/Binaries/Debug/libwebsocketclient_test.a; sourceTree = ""; }; - D52BABAA1A1C064100FAE04C /* libwebsockettest_utilities.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libwebsockettest_utilities.a; path = ../../../../../Build_iOS/build.debug/build.i386/Binaries/Debug/libwebsockettest_utilities.a; sourceTree = ""; }; - D5E513891A1BEA1D0060F252 /* ios_runnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ios_runnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - D5E5138E1A1BEA1D0060F252 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - D5E5138F1A1BEA1D0060F252 /* ios_runnerTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ios_runnerTests.mm; sourceTree = ""; }; - D5E513991A1BFDD80060F252 /* libunittestpp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libunittestpp.a; path = ../../../../../Build_iOS/build.debug/build.i386/Binaries/Debug/libunittestpp.a; sourceTree = ""; }; - D5E5139B1A1BFECD0060F252 /* libcpprest.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcpprest.a; path = ../../../../../Build_iOS/build.debug/build.i386/Binaries/Debug/libcpprest.a; sourceTree = ""; }; - D5E5139D1A1BFEE20060F252 /* libcommon_utilities.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcommon_utilities.a; path = ../../../../../Build_iOS/build.debug/build.i386/Binaries/Debug/libcommon_utilities.a; sourceTree = ""; }; - D5E5139E1A1BFEE20060F252 /* libhttpclient_test.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libhttpclient_test.a; path = ../../../../../Build_iOS/build.debug/build.i386/Binaries/Debug/libhttpclient_test.a; sourceTree = ""; }; - D5E5139F1A1BFEE20060F252 /* libhttplistener_test.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libhttplistener_test.a; path = ../../../../../Build_iOS/build.debug/build.i386/Binaries/Debug/libhttplistener_test.a; sourceTree = ""; }; - D5E513A01A1BFEE20060F252 /* libhttptest_utilities.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libhttptest_utilities.a; path = ../../../../../Build_iOS/build.debug/build.i386/Binaries/Debug/libhttptest_utilities.a; sourceTree = ""; }; - D5E513A11A1BFEE20060F252 /* libjson_test.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libjson_test.a; path = ../../../../../Build_iOS/build.debug/build.i386/Binaries/Debug/libjson_test.a; sourceTree = ""; }; - D5E513A21A1BFEE20060F252 /* libpplx_test.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpplx_test.a; path = ../../../../../Build_iOS/build.debug/build.i386/Binaries/Debug/libpplx_test.a; sourceTree = ""; }; - D5E513A31A1BFEE20060F252 /* libstreams_test.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libstreams_test.a; path = ../../../../../Build_iOS/build.debug/build.i386/Binaries/Debug/libstreams_test.a; sourceTree = ""; }; - D5E513A41A1BFEE20060F252 /* liburi_test.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = liburi_test.a; path = ../../../../../Build_iOS/build.debug/build.i386/Binaries/Debug/liburi_test.a; sourceTree = ""; }; - D5E513A51A1BFEE20060F252 /* libutils_test.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libutils_test.a; path = ../../../../../Build_iOS/build.debug/build.i386/Binaries/Debug/libutils_test.a; sourceTree = ""; }; - D5E513AF1A1C01820060F252 /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = usr/lib/libiconv.dylib; sourceTree = SDKROOT; }; - D5E513B11A1C01D30060F252 /* boost.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = boost.framework; path = ../../../../../Build_iOS/boost.framework; sourceTree = ""; }; - D5E513B21A1C02200060F252 /* libcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcrypto.a; path = ../../../../../Build_iOS/openssl/lib/libcrypto.a; sourceTree = ""; }; - D5E513B31A1C02210060F252 /* libssl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libssl.a; path = ../../../../../Build_iOS/openssl/lib/libssl.a; sourceTree = ""; }; - D5E513B61A1C02570060F252 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - D5E513861A1BEA1D0060F252 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - D5E513B81A1C02CF0060F252 /* boost.framework in Frameworks */, - D5E513B71A1C02570060F252 /* Security.framework in Frameworks */, - D5E513B41A1C02210060F252 /* libcrypto.a in Frameworks */, - D5E513B51A1C02210060F252 /* libssl.a in Frameworks */, - D5E513B01A1C01820060F252 /* libiconv.dylib in Frameworks */, - D5E513A61A1BFEE20060F252 /* libcommon_utilities.a in Frameworks */, - D5E513A71A1BFEE20060F252 /* libhttpclient_test.a in Frameworks */, - D5E513A81A1BFEE20060F252 /* libhttplistener_test.a in Frameworks */, - D5E513A91A1BFEE20060F252 /* libhttptest_utilities.a in Frameworks */, - D5E513AA1A1BFEE20060F252 /* libjson_test.a in Frameworks */, - D5E513AB1A1BFEE20060F252 /* libpplx_test.a in Frameworks */, - D5E513AC1A1BFEE20060F252 /* libstreams_test.a in Frameworks */, - D5E513AD1A1BFEE20060F252 /* liburi_test.a in Frameworks */, - D5E513AE1A1BFEE20060F252 /* libutils_test.a in Frameworks */, - D5E5139C1A1BFECD0060F252 /* libcpprest.a in Frameworks */, - D5E5139A1A1BFDD80060F252 /* libunittestpp.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - D5E513671A1BEA1D0060F252 = { - isa = PBXGroup; - children = ( - D52BABA91A1C064100FAE04C /* libwebsocketclient_test.a */, - D52BABAA1A1C064100FAE04C /* libwebsockettest_utilities.a */, - D5E513B61A1C02570060F252 /* Security.framework */, - D5E513B21A1C02200060F252 /* libcrypto.a */, - D5E513B31A1C02210060F252 /* libssl.a */, - D5E513B11A1C01D30060F252 /* boost.framework */, - D5E513AF1A1C01820060F252 /* libiconv.dylib */, - D5E5139D1A1BFEE20060F252 /* libcommon_utilities.a */, - D5E5139E1A1BFEE20060F252 /* libhttpclient_test.a */, - D5E5139F1A1BFEE20060F252 /* libhttplistener_test.a */, - D5E513A01A1BFEE20060F252 /* libhttptest_utilities.a */, - D5E513A11A1BFEE20060F252 /* libjson_test.a */, - D5E513A21A1BFEE20060F252 /* libpplx_test.a */, - D5E513A31A1BFEE20060F252 /* libstreams_test.a */, - D5E513A41A1BFEE20060F252 /* liburi_test.a */, - D5E513A51A1BFEE20060F252 /* libutils_test.a */, - D5E5139B1A1BFECD0060F252 /* libcpprest.a */, - D5E513991A1BFDD80060F252 /* libunittestpp.a */, - D5E5138C1A1BEA1D0060F252 /* ios_runnerTests */, - D5E513711A1BEA1D0060F252 /* Products */, - ); - sourceTree = ""; - }; - D5E513711A1BEA1D0060F252 /* Products */ = { - isa = PBXGroup; - children = ( - D5E513891A1BEA1D0060F252 /* ios_runnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - D5E5138C1A1BEA1D0060F252 /* ios_runnerTests */ = { - isa = PBXGroup; - children = ( - D5E5138F1A1BEA1D0060F252 /* ios_runnerTests.mm */, - D5E5138D1A1BEA1D0060F252 /* Supporting Files */, - ); - path = ios_runnerTests; - sourceTree = ""; - }; - D5E5138D1A1BEA1D0060F252 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - D5E5138E1A1BEA1D0060F252 /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - D5E513881A1BEA1D0060F252 /* ios_runnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = D5E513961A1BEA1D0060F252 /* Build configuration list for PBXNativeTarget "ios_runnerTests" */; - buildPhases = ( - D5E513851A1BEA1D0060F252 /* Sources */, - D5E513861A1BEA1D0060F252 /* Frameworks */, - D5E513871A1BEA1D0060F252 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ios_runnerTests; - productName = ios_runnerTests; - productReference = D5E513891A1BEA1D0060F252 /* ios_runnerTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - D5E513681A1BEA1D0060F252 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0610; - ORGANIZATIONNAME = "Steve Gates"; - TargetAttributes = { - D5E513881A1BEA1D0060F252 = { - CreatedOnToolsVersion = 6.1; - }; - }; - }; - buildConfigurationList = D5E5136B1A1BEA1D0060F252 /* Build configuration list for PBXProject "ios_runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = D5E513671A1BEA1D0060F252; - productRefGroup = D5E513711A1BEA1D0060F252 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - D5E513881A1BEA1D0060F252 /* ios_runnerTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - D5E513871A1BEA1D0060F252 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - D5E513851A1BEA1D0060F252 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - D5E513901A1BEA1D0060F252 /* ios_runnerTests.mm in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - D5E513911A1BEA1D0060F252 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.1; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = NO; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - USER_HEADER_SEARCH_PATHS = ../../unittestpp/; - VALID_ARCHS = i386; - }; - name = Debug; - }; - D5E513921A1BEA1D0060F252 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = YES; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.1; - MTL_ENABLE_DEBUG_INFO = NO; - ONLY_ACTIVE_ARCH = NO; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - USER_HEADER_SEARCH_PATHS = ../../unittestpp/; - VALIDATE_PRODUCT = YES; - VALID_ARCHS = i386; - }; - name = Release; - }; - D5E513971A1BEA1D0060F252 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - ../../../../../Build_iOS, - ); - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = ios_runnerTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - ../../../../../Build_iOS/build.debug/build.i386/Binaries/Debug, - ../../../../../Build_iOS/openssl/lib, - ); - OTHER_LDFLAGS = ( - "$(inherited)", - "-all_load", - "-framework", - XCTest, - ); - PRODUCT_NAME = "$(TARGET_NAME)"; - USER_HEADER_SEARCH_PATHS = "../../unittestpp/ ../../../../include ../../../../../Build_iOS/boost.framework/Headers"; - }; - name = Debug; - }; - D5E513981A1BEA1D0060F252 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - ../../../../../Build_iOS, - ); - INFOPLIST_FILE = ios_runnerTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - ../../../../../Build_iOS/build.release/build.i386/Binaries/Release, - ../../../../../Build_iOS/openssl/lib, - ); - OTHER_LDFLAGS = ( - "$(inherited)", - "-all_load", - "-framework", - XCTest, - ); - PRODUCT_NAME = "$(TARGET_NAME)"; - USER_HEADER_SEARCH_PATHS = "../../unittestpp/ ../../../../include ../../../../../Build_iOS/boost.framework/Headers"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - D5E5136B1A1BEA1D0060F252 /* Build configuration list for PBXProject "ios_runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - D5E513911A1BEA1D0060F252 /* Debug */, - D5E513921A1BEA1D0060F252 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - D5E513961A1BEA1D0060F252 /* Build configuration list for PBXNativeTarget "ios_runnerTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - D5E513971A1BEA1D0060F252 /* Debug */, - D5E513981A1BEA1D0060F252 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = D5E513681A1BEA1D0060F252 /* Project object */; -} diff --git a/Release/tests/common/TestRunner/ios/ios_runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Release/tests/common/TestRunner/ios/ios_runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index f7799a8bc6..0000000000 --- a/Release/tests/common/TestRunner/ios/ios_runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Release/tests/common/TestRunner/ios/ios_runner.xcodeproj/xcshareddata/xcschemes/ios_runner.xcscheme b/Release/tests/common/TestRunner/ios/ios_runner.xcodeproj/xcshareddata/xcschemes/ios_runner.xcscheme deleted file mode 100644 index bef34bb582..0000000000 --- a/Release/tests/common/TestRunner/ios/ios_runner.xcodeproj/xcshareddata/xcschemes/ios_runner.xcscheme +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/common/TestRunner/ios/ios_runnerTests/Info.plist b/Release/tests/common/TestRunner/ios/ios_runnerTests/Info.plist deleted file mode 100644 index 04f6d96780..0000000000 --- a/Release/tests/common/TestRunner/ios/ios_runnerTests/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - blah.$(PRODUCT_NAME:rfc1034identifier) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - - diff --git a/Release/tests/common/TestRunner/ios/ios_runnerTests/ios_runnerTests.mm b/Release/tests/common/TestRunner/ios/ios_runnerTests/ios_runnerTests.mm deleted file mode 100644 index b0f578a59f..0000000000 --- a/Release/tests/common/TestRunner/ios/ios_runnerTests/ios_runnerTests.mm +++ /dev/null @@ -1,67 +0,0 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* ==--== -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* Creates an Xcode test to bride with our UnitTestpp tests. Can be used to run -* iOS tests in the simulator or a connected physically device. -* -* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ -#import -#import - -#include "unittestpp.h" -#include "src/TestReporterStdout.h" - -@interface ios_runnerTests : XCTestCase - -@end - -@implementation ios_runnerTests - -- (void)setUp { - [super setUp]; - // Put setup code here. This method is called before the invocation of each test method in the class. -} - -- (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - -- (void)testCppRestSdk { - UnitTest::TestReporterStdout testReporter; - UnitTest::TestRunner testRunner(testReporter); - - UnitTest::TestList& tests = UnitTest::GetTestList(); - testRunner.RunTestsIf(tests, - [&](UnitTest::Test *pTest) - { - if (pTest->m_properties.Has("Ignore")) return false; - if (pTest->m_properties.Has("Ignore:Apple")) return false; - if (pTest->m_properties.Has("Ignore:IOS")) return false; - if (pTest->m_properties.Has("Requires")) return false; - return true; - }, - 60000 * 3); - - int totalTestCount = testRunner.GetTestResults()->GetTotalTestCount(); - int failedTestCount = testRunner.GetTestResults()->GetFailedTestCount(); - if(failedTestCount > 0) - { - printf("%i tests FAILED\n", failedTestCount); - XCTAssert(false); - } - else - { - printf("All %i tests PASSED\n", totalTestCount); - XCTAssert(YES, @"Pass"); - } -} - -@end diff --git a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/TestRunner.android.NativeActivity.vcxproj b/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/TestRunner.android.NativeActivity.vcxproj deleted file mode 100644 index d798ca823d..0000000000 --- a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/TestRunner.android.NativeActivity.vcxproj +++ /dev/null @@ -1,284 +0,0 @@ - - - - - Debug - ARM - - - Debug - x86 - - - Release - ARM - - - Release - x86 - - - - {d1060d0a-a10e-444d-9f6b-9676ea453f9a} - Android - TestRunner.android.NativeActivity - TestRunner_android - en-US - 14.0 - Android - 2.0 - - - - DynamicLibrary - true - gnustl_static - Clang_3_8 - - - DynamicLibrary - true - gnustl_static - Clang_3_8 - - - DynamicLibrary - false - gnustl_static - Clang_3_8 - - - DynamicLibrary - false - gnustl_static - Clang_3_8 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Use - pch.h - CompileAsCpp - Enabled - true - c++11 - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - %(LibraryDependencies);GLESv1_CM;EGL;m - - - - - Use - pch.h - CompileAsCpp - Enabled - true - c++11 - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - %(LibraryDependencies);GLESv1_CM;EGL;m - - - - - Use - pch.h - CompileAsCpp - Enabled - true - c++11 - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - %(LibraryDependencies);GLESv1_CM;EGL;m - - - - - Use - pch.h - CompileAsCpp - Enabled - true - c++11 - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - %(LibraryDependencies);GLESv1_CM;EGL;m - - - - - - - - - - - - - {afb49019-965b-4c10-baff-c86c16d58010} - true - false - false - true - true - - - {0ee481da-a97f-4831-9119-c65eb2d7b4da} - true - false - false - true - true - - - {2b00d1c0-1a93-4a32-8932-c3cc43acff45} - true - false - false - true - true - - - {b444ee47-1340-4a74-820d-cdd55f9f22f7} - true - false - false - true - true - - - {169555ef-8a80-405e-a815-cfe70028ca45} - true - false - false - true - true - - - {df670b4e-692c-424e-bcfd-f63d34fe5cd3} - true - false - false - true - true - - - {b9da540f-95f7-485e-adf4-c94a17bfa1eb} - true - false - false - true - true - - - {63569c1a-a168-442a-b160-76d0256803af} - true - false - false - true - true - - - {423fce6d-7400-4c09-9038-4438fbb089d4} - true - false - false - true - true - - - {3e8466b1-7cbc-489d-8e6b-5e45bab4d627} - true - false - false - true - true - - - {0149e1c2-fbf3-48b6-9996-d6753f689dfb} - true - false - false - true - true - - - {3efd8540-a54d-4900-887e-f856162535a0} - true - false - false - true - true - - - {7c4e6e33-42e2-4472-9319-dde7564f3dae} - true - false - false - true - true - - - - - - - - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/TestRunner.android.NativeActivity.vcxproj.filters b/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/TestRunner.android.NativeActivity.vcxproj.filters deleted file mode 100644 index 52b354d8e3..0000000000 --- a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/TestRunner.android.NativeActivity.vcxproj.filters +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/android_native_app_glue.c b/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/android_native_app_glue.c deleted file mode 100644 index 6de5362a00..0000000000 --- a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/android_native_app_glue.c +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__)) -#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "threaded_app", __VA_ARGS__)) - -/* For debug builds, always enable the debug traces in this library */ -#ifndef NDEBUG -# define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "threaded_app", __VA_ARGS__)) -#else -# define LOGV(...) ((void)0) -#endif - -static void free_saved_state(struct android_app* android_app) { - pthread_mutex_lock(&android_app->mutex); - if (android_app->savedState != NULL) { - free(android_app->savedState); - android_app->savedState = NULL; - android_app->savedStateSize = 0; - } - pthread_mutex_unlock(&android_app->mutex); -} - -int8_t android_app_read_cmd(struct android_app* android_app) { - int8_t cmd; - if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) { - switch (cmd) { - case APP_CMD_SAVE_STATE: - free_saved_state(android_app); - break; - } - return cmd; - } else { - LOGE("No data on command pipe!"); - } - return -1; -} - -static void print_cur_config(struct android_app* android_app) { - char lang[2], country[2]; - AConfiguration_getLanguage(android_app->config, lang); - AConfiguration_getCountry(android_app->config, country); - - LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d " - "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d " - "modetype=%d modenight=%d", - AConfiguration_getMcc(android_app->config), - AConfiguration_getMnc(android_app->config), - lang[0], lang[1], country[0], country[1], - AConfiguration_getOrientation(android_app->config), - AConfiguration_getTouchscreen(android_app->config), - AConfiguration_getDensity(android_app->config), - AConfiguration_getKeyboard(android_app->config), - AConfiguration_getNavigation(android_app->config), - AConfiguration_getKeysHidden(android_app->config), - AConfiguration_getNavHidden(android_app->config), - AConfiguration_getSdkVersion(android_app->config), - AConfiguration_getScreenSize(android_app->config), - AConfiguration_getScreenLong(android_app->config), - AConfiguration_getUiModeType(android_app->config), - AConfiguration_getUiModeNight(android_app->config)); -} - -void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) { - switch (cmd) { - case APP_CMD_INPUT_CHANGED: - LOGV("APP_CMD_INPUT_CHANGED\n"); - pthread_mutex_lock(&android_app->mutex); - if (android_app->inputQueue != NULL) { - AInputQueue_detachLooper(android_app->inputQueue); - } - android_app->inputQueue = android_app->pendingInputQueue; - if (android_app->inputQueue != NULL) { - LOGV("Attaching input queue to looper"); - AInputQueue_attachLooper(android_app->inputQueue, - android_app->looper, LOOPER_ID_INPUT, NULL, - &android_app->inputPollSource); - } - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_INIT_WINDOW: - LOGV("APP_CMD_INIT_WINDOW\n"); - pthread_mutex_lock(&android_app->mutex); - android_app->window = android_app->pendingWindow; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_TERM_WINDOW: - LOGV("APP_CMD_TERM_WINDOW\n"); - pthread_cond_broadcast(&android_app->cond); - break; - - case APP_CMD_RESUME: - case APP_CMD_START: - case APP_CMD_PAUSE: - case APP_CMD_STOP: - LOGV("activityState=%d\n", cmd); - pthread_mutex_lock(&android_app->mutex); - android_app->activityState = cmd; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_CONFIG_CHANGED: - LOGV("APP_CMD_CONFIG_CHANGED\n"); - AConfiguration_fromAssetManager(android_app->config, - android_app->activity->assetManager); - print_cur_config(android_app); - break; - - case APP_CMD_DESTROY: - LOGV("APP_CMD_DESTROY\n"); - android_app->destroyRequested = 1; - break; - } -} - -void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) { - switch (cmd) { - case APP_CMD_TERM_WINDOW: - LOGV("APP_CMD_TERM_WINDOW\n"); - pthread_mutex_lock(&android_app->mutex); - android_app->window = NULL; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_SAVE_STATE: - LOGV("APP_CMD_SAVE_STATE\n"); - pthread_mutex_lock(&android_app->mutex); - android_app->stateSaved = 1; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_RESUME: - free_saved_state(android_app); - break; - } -} - -static void android_app_destroy(struct android_app* android_app) { - LOGV("android_app_destroy!"); - free_saved_state(android_app); - pthread_mutex_lock(&android_app->mutex); - if (android_app->inputQueue != NULL) { - AInputQueue_detachLooper(android_app->inputQueue); - } - AConfiguration_delete(android_app->config); - android_app->destroyed = 1; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - // Can't touch android_app object after this. -} - -static void process_input(struct android_app* app, struct android_poll_source* source) { - AInputEvent* event = NULL; - while (AInputQueue_getEvent(app->inputQueue, &event) >= 0) { - LOGV("New input event: type=%d\n", AInputEvent_getType(event)); - if (AInputQueue_preDispatchEvent(app->inputQueue, event)) { - continue; - } - int32_t handled = 0; - if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event); - AInputQueue_finishEvent(app->inputQueue, event, handled); - } -} - -static void process_cmd(struct android_app* app, struct android_poll_source* source) { - int8_t cmd = android_app_read_cmd(app); - android_app_pre_exec_cmd(app, cmd); - if (app->onAppCmd != NULL) app->onAppCmd(app, cmd); - android_app_post_exec_cmd(app, cmd); -} - -static void* android_app_entry(void* param) { - struct android_app* android_app = (struct android_app*)param; - - android_app->config = AConfiguration_new(); - AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager); - - print_cur_config(android_app); - - android_app->cmdPollSource.id = LOOPER_ID_MAIN; - android_app->cmdPollSource.app = android_app; - android_app->cmdPollSource.process = process_cmd; - android_app->inputPollSource.id = LOOPER_ID_INPUT; - android_app->inputPollSource.app = android_app; - android_app->inputPollSource.process = process_input; - - ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); - ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL, - &android_app->cmdPollSource); - android_app->looper = looper; - - pthread_mutex_lock(&android_app->mutex); - android_app->running = 1; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - - android_main(android_app); - - android_app_destroy(android_app); - return NULL; -} - -// -------------------------------------------------------------------- -// Native activity interaction (called from main thread) -// -------------------------------------------------------------------- - -static struct android_app* android_app_create(ANativeActivity* activity, - void* savedState, size_t savedStateSize) { - struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app)); - memset(android_app, 0, sizeof(struct android_app)); - android_app->activity = activity; - - pthread_mutex_init(&android_app->mutex, NULL); - pthread_cond_init(&android_app->cond, NULL); - - if (savedState != NULL) { - android_app->savedState = malloc(savedStateSize); - android_app->savedStateSize = savedStateSize; - memcpy(android_app->savedState, savedState, savedStateSize); - } - - int msgpipe[2]; - if (pipe(msgpipe)) { - LOGE("could not create pipe: %s", strerror(errno)); - return NULL; - } - android_app->msgread = msgpipe[0]; - android_app->msgwrite = msgpipe[1]; - - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_create(&android_app->thread, &attr, android_app_entry, android_app); - - // Wait for thread to start. - pthread_mutex_lock(&android_app->mutex); - while (!android_app->running) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); - - return android_app; -} - -static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) { - if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) { - LOGE("Failure writing android_app cmd: %s\n", strerror(errno)); - } -} - -static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) { - pthread_mutex_lock(&android_app->mutex); - android_app->pendingInputQueue = inputQueue; - android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED); - while (android_app->inputQueue != android_app->pendingInputQueue) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); -} - -static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) { - pthread_mutex_lock(&android_app->mutex); - if (android_app->pendingWindow != NULL) { - android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW); - } - android_app->pendingWindow = window; - if (window != NULL) { - android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW); - } - while (android_app->window != android_app->pendingWindow) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); -} - -static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) { - pthread_mutex_lock(&android_app->mutex); - android_app_write_cmd(android_app, cmd); - while (android_app->activityState != cmd) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); -} - -static void android_app_free(struct android_app* android_app) { - pthread_mutex_lock(&android_app->mutex); - android_app_write_cmd(android_app, APP_CMD_DESTROY); - while (!android_app->destroyed) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); - - close(android_app->msgread); - close(android_app->msgwrite); - pthread_cond_destroy(&android_app->cond); - pthread_mutex_destroy(&android_app->mutex); - free(android_app); -} - -static void onDestroy(ANativeActivity* activity) { - LOGV("Destroy: %p\n", activity); - android_app_free((struct android_app*)activity->instance); -} - -static void onStart(ANativeActivity* activity) { - LOGV("Start: %p\n", activity); - android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START); -} - -static void onResume(ANativeActivity* activity) { - LOGV("Resume: %p\n", activity); - android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME); -} - -static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) { - struct android_app* android_app = (struct android_app*)activity->instance; - void* savedState = NULL; - - LOGV("SaveInstanceState: %p\n", activity); - pthread_mutex_lock(&android_app->mutex); - android_app->stateSaved = 0; - android_app_write_cmd(android_app, APP_CMD_SAVE_STATE); - while (!android_app->stateSaved) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - - if (android_app->savedState != NULL) { - savedState = android_app->savedState; - *outLen = android_app->savedStateSize; - android_app->savedState = NULL; - android_app->savedStateSize = 0; - } - - pthread_mutex_unlock(&android_app->mutex); - - return savedState; -} - -static void onPause(ANativeActivity* activity) { - LOGV("Pause: %p\n", activity); - android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE); -} - -static void onStop(ANativeActivity* activity) { - LOGV("Stop: %p\n", activity); - android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP); -} - -static void onConfigurationChanged(ANativeActivity* activity) { - struct android_app* android_app = (struct android_app*)activity->instance; - LOGV("ConfigurationChanged: %p\n", activity); - android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED); -} - -static void onLowMemory(ANativeActivity* activity) { - struct android_app* android_app = (struct android_app*)activity->instance; - LOGV("LowMemory: %p\n", activity); - android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY); -} - -static void onWindowFocusChanged(ANativeActivity* activity, int focused) { - LOGV("WindowFocusChanged: %p -- %d\n", activity, focused); - android_app_write_cmd((struct android_app*)activity->instance, - focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS); -} - -static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) { - LOGV("NativeWindowCreated: %p -- %p\n", activity, window); - android_app_set_window((struct android_app*)activity->instance, window); -} - -static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) { - LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window); - android_app_set_window((struct android_app*)activity->instance, NULL); -} - -static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) { - LOGV("InputQueueCreated: %p -- %p\n", activity, queue); - android_app_set_input((struct android_app*)activity->instance, queue); -} - -static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) { - LOGV("InputQueueDestroyed: %p -- %p\n", activity, queue); - android_app_set_input((struct android_app*)activity->instance, NULL); -} - -void ANativeActivity_onCreate(ANativeActivity* activity, - void* savedState, size_t savedStateSize) { - LOGV("Creating: %p\n", activity); - activity->callbacks->onDestroy = onDestroy; - activity->callbacks->onStart = onStart; - activity->callbacks->onResume = onResume; - activity->callbacks->onSaveInstanceState = onSaveInstanceState; - activity->callbacks->onPause = onPause; - activity->callbacks->onStop = onStop; - activity->callbacks->onConfigurationChanged = onConfigurationChanged; - activity->callbacks->onLowMemory = onLowMemory; - activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; - activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; - activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; - activity->callbacks->onInputQueueCreated = onInputQueueCreated; - activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; - - activity->instance = android_app_create(activity, savedState, savedStateSize); -} diff --git a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/android_native_app_glue.h b/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/android_native_app_glue.h deleted file mode 100644 index 1b390c2d46..0000000000 --- a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/android_native_app_glue.h +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef _ANDROID_NATIVE_APP_GLUE_H -#define _ANDROID_NATIVE_APP_GLUE_H - -#include -#include -#include - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * The native activity interface provided by - * is based on a set of application-provided callbacks that will be called - * by the Activity's main thread when certain events occur. - * - * This means that each one of this callbacks _should_ _not_ block, or they - * risk having the system force-close the application. This programming - * model is direct, lightweight, but constraining. - * - * The 'threaded_native_app' static library is used to provide a different - * execution model where the application can implement its own main event - * loop in a different thread instead. Here's how it works: - * - * 1/ The application must provide a function named "android_main()" that - * will be called when the activity is created, in a new thread that is - * distinct from the activity's main thread. - * - * 2/ android_main() receives a pointer to a valid "android_app" structure - * that contains references to other important objects, e.g. the - * ANativeActivity obejct instance the application is running in. - * - * 3/ the "android_app" object holds an ALooper instance that already - * listens to two important things: - * - * - activity lifecycle events (e.g. "pause", "resume"). See APP_CMD_XXX - * declarations below. - * - * - input events coming from the AInputQueue attached to the activity. - * - * Each of these correspond to an ALooper identifier returned by - * ALooper_pollOnce with values of LOOPER_ID_MAIN and LOOPER_ID_INPUT, - * respectively. - * - * Your application can use the same ALooper to listen to additional - * file-descriptors. They can either be callback based, or with return - * identifiers starting with LOOPER_ID_USER. - * - * 4/ Whenever you receive a LOOPER_ID_MAIN or LOOPER_ID_INPUT event, - * the returned data will point to an android_poll_source structure. You - * can call the process() function on it, and fill in android_app->onAppCmd - * and android_app->onInputEvent to be called for your own processing - * of the event. - * - * Alternatively, you can call the low-level functions to read and process - * the data directly... look at the process_cmd() and process_input() - * implementations in the glue to see how to do this. - * - * See the sample named "native-activity" that comes with the NDK with a - * full usage example. Also look at the JavaDoc of NativeActivity. - */ - -struct android_app; - -/** - * Data associated with an ALooper fd that will be returned as the "outData" - * when that source has data ready. - */ -struct android_poll_source { - // The identifier of this source. May be LOOPER_ID_MAIN or - // LOOPER_ID_INPUT. - int32_t id; - - // The android_app this ident is associated with. - struct android_app* app; - - // Function to call to perform the standard processing of data from - // this source. - void (*process)(struct android_app* app, struct android_poll_source* source); -}; - -/** - * This is the interface for the standard glue code of a threaded - * application. In this model, the application's code is running - * in its own thread separate from the main thread of the process. - * It is not required that this thread be associated with the Java - * VM, although it will need to be in order to make JNI calls any - * Java objects. - */ -struct android_app { - // The application can place a pointer to its own state object - // here if it likes. - void* userData; - - // Fill this in with the function to process main app commands (APP_CMD_*) - void (*onAppCmd)(struct android_app* app, int32_t cmd); - - // Fill this in with the function to process input events. At this point - // the event has already been pre-dispatched, and it will be finished upon - // return. Return 1 if you have handled the event, 0 for any default - // dispatching. - int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event); - - // The ANativeActivity object instance that this app is running in. - ANativeActivity* activity; - - // The current configuration the app is running in. - AConfiguration* config; - - // This is the last instance's saved state, as provided at creation time. - // It is NULL if there was no state. You can use this as you need; the - // memory will remain around until you call android_app_exec_cmd() for - // APP_CMD_RESUME, at which point it will be freed and savedState set to NULL. - // These variables should only be changed when processing a APP_CMD_SAVE_STATE, - // at which point they will be initialized to NULL and you can malloc your - // state and place the information here. In that case the memory will be - // freed for you later. - void* savedState; - size_t savedStateSize; - - // The ALooper associated with the app's thread. - ALooper* looper; - - // When non-NULL, this is the input queue from which the app will - // receive user input events. - AInputQueue* inputQueue; - - // When non-NULL, this is the window surface that the app can draw in. - ANativeWindow* window; - - // Current content rectangle of the window; this is the area where the - // window's content should be placed to be seen by the user. - ARect contentRect; - - // Current state of the app's activity. May be either APP_CMD_START, - // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below. - int activityState; - - // This is non-zero when the application's NativeActivity is being - // destroyed and waiting for the app thread to complete. - int destroyRequested; - - // ------------------------------------------------- - // Below are "private" implementation of the glue code. - - pthread_mutex_t mutex; - pthread_cond_t cond; - - int msgread; - int msgwrite; - - pthread_t thread; - - struct android_poll_source cmdPollSource; - struct android_poll_source inputPollSource; - - int running; - int stateSaved; - int destroyed; - int redrawNeeded; - AInputQueue* pendingInputQueue; - ANativeWindow* pendingWindow; - ARect pendingContentRect; -}; - -enum { - /** - * Looper data ID of commands coming from the app's main thread, which - * is returned as an identifier from ALooper_pollOnce(). The data for this - * identifier is a pointer to an android_poll_source structure. - * These can be retrieved and processed with android_app_read_cmd() - * and android_app_exec_cmd(). - */ - LOOPER_ID_MAIN = 1, - - /** - * Looper data ID of events coming from the AInputQueue of the - * application's window, which is returned as an identifier from - * ALooper_pollOnce(). The data for this identifier is a pointer to an - * android_poll_source structure. These can be read via the inputQueue - * object of android_app. - */ - LOOPER_ID_INPUT = 2, - - /** - * Start of user-defined ALooper identifiers. - */ - LOOPER_ID_USER = 3, -}; - -enum { - /** - * Command from main thread: the AInputQueue has changed. Upon processing - * this command, android_app->inputQueue will be updated to the new queue - * (or NULL). - */ - APP_CMD_INPUT_CHANGED, - - /** - * Command from main thread: a new ANativeWindow is ready for use. Upon - * receiving this command, android_app->window will contain the new window - * surface. - */ - APP_CMD_INIT_WINDOW, - - /** - * Command from main thread: the existing ANativeWindow needs to be - * terminated. Upon receiving this command, android_app->window still - * contains the existing window; after calling android_app_exec_cmd - * it will be set to NULL. - */ - APP_CMD_TERM_WINDOW, - - /** - * Command from main thread: the current ANativeWindow has been resized. - * Please redraw with its new size. - */ - APP_CMD_WINDOW_RESIZED, - - /** - * Command from main thread: the system needs that the current ANativeWindow - * be redrawn. You should redraw the window before handing this to - * android_app_exec_cmd() in order to avoid transient drawing glitches. - */ - APP_CMD_WINDOW_REDRAW_NEEDED, - - /** - * Command from main thread: the content area of the window has changed, - * such as from the soft input window being shown or hidden. You can - * find the new content rect in android_app::contentRect. - */ - APP_CMD_CONTENT_RECT_CHANGED, - - /** - * Command from main thread: the app's activity window has gained - * input focus. - */ - APP_CMD_GAINED_FOCUS, - - /** - * Command from main thread: the app's activity window has lost - * input focus. - */ - APP_CMD_LOST_FOCUS, - - /** - * Command from main thread: the current device configuration has changed. - */ - APP_CMD_CONFIG_CHANGED, - - /** - * Command from main thread: the system is running low on memory. - * Try to reduce your memory use. - */ - APP_CMD_LOW_MEMORY, - - /** - * Command from main thread: the app's activity has been started. - */ - APP_CMD_START, - - /** - * Command from main thread: the app's activity has been resumed. - */ - APP_CMD_RESUME, - - /** - * Command from main thread: the app should generate a new saved state - * for itself, to restore from later if needed. If you have saved state, - * allocate it with malloc and place it in android_app.savedState with - * the size in android_app.savedStateSize. The will be freed for you - * later. - */ - APP_CMD_SAVE_STATE, - - /** - * Command from main thread: the app's activity has been paused. - */ - APP_CMD_PAUSE, - - /** - * Command from main thread: the app's activity has been stopped. - */ - APP_CMD_STOP, - - /** - * Command from main thread: the app's activity is being destroyed, - * and waiting for the app thread to clean up and exit before proceeding. - */ - APP_CMD_DESTROY, -}; - -/** - * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next - * app command message. - */ -int8_t android_app_read_cmd(struct android_app* android_app); - -/** - * Call with the command returned by android_app_read_cmd() to do the - * initial pre-processing of the given command. You can perform your own - * actions for the command after calling this function. - */ -void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd); - -/** - * Call with the command returned by android_app_read_cmd() to do the - * final post-processing of the given command. You must have done your own - * actions for the command before calling this function. - */ -void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd); - -/** - * This is the function that application code must implement, representing - * the main entry to the app. - */ -extern void android_main(struct android_app* app); - -#ifdef __cplusplus -} -#endif - -#endif /* _ANDROID_NATIVE_APP_GLUE_H */ diff --git a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/main.cpp b/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/main.cpp deleted file mode 100644 index d6333e1fd5..0000000000 --- a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/main.cpp +++ /dev/null @@ -1,437 +0,0 @@ -/* -* Copyright (C) 2010 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -*/ - -#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "AndroidProject1.NativeActivity", __VA_ARGS__)) -#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "AndroidProject1.NativeActivity", __VA_ARGS__)) - -/** -* Our saved state data. -*/ -struct saved_state { - float angle; - int32_t x; - int32_t y; -}; - -/** -* Shared state for our app. -*/ -struct engine { - struct android_app* app; - - ASensorManager* sensorManager; - const ASensor* accelerometerSensor; - ASensorEventQueue* sensorEventQueue; - - int animating; - EGLDisplay display; - EGLSurface surface; - EGLContext context; - int32_t width; - int32_t height; - struct saved_state state; -}; - -/** -* Initialize an EGL context for the current display. -*/ -static int engine_init_display(struct engine* engine) { - // initialize OpenGL ES and EGL - - /* - * Here specify the attributes of the desired configuration. - * Below, we select an EGLConfig with at least 8 bits per color - * component compatible with on-screen windows - */ - const EGLint attribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_BLUE_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_RED_SIZE, 8, - EGL_NONE - }; - EGLint w, h, format; - EGLint numConfigs; - EGLConfig config; - EGLSurface surface; - EGLContext context; - - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - - eglInitialize(display, 0, 0); - - /* Here, the application chooses the configuration it desires. In this - * sample, we have a very simplified selection process, where we pick - * the first EGLConfig that matches our criteria */ - eglChooseConfig(display, attribs, &config, 1, &numConfigs); - - /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is - * guaranteed to be accepted by ANativeWindow_setBuffersGeometry(). - * As soon as we picked a EGLConfig, we can safely reconfigure the - * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */ - eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format); - - ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format); - - surface = eglCreateWindowSurface(display, config, engine->app->window, NULL); - context = eglCreateContext(display, config, NULL, NULL); - - if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { - LOGW("Unable to eglMakeCurrent"); - return -1; - } - - eglQuerySurface(display, surface, EGL_WIDTH, &w); - eglQuerySurface(display, surface, EGL_HEIGHT, &h); - - engine->display = display; - engine->context = context; - engine->surface = surface; - engine->width = w; - engine->height = h; - engine->state.angle = 0; - - // Initialize GL state. - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); - glEnable(GL_CULL_FACE); - glShadeModel(GL_SMOOTH); - glDisable(GL_DEPTH_TEST); - - return 0; -} - -/** -* Just the current frame in the display. -*/ -static void engine_draw_frame(struct engine* engine) { - if (engine->display == NULL) { - // No display. - return; - } - - // Just fill the screen with a color. - glClearColor(((float)engine->state.x) / engine->width, engine->state.angle, - ((float)engine->state.y) / engine->height, 1); - glClear(GL_COLOR_BUFFER_BIT); - - eglSwapBuffers(engine->display, engine->surface); -} - -/** -* Tear down the EGL context currently associated with the display. -*/ -static void engine_term_display(struct engine* engine) { - if (engine->display != EGL_NO_DISPLAY) { - eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (engine->context != EGL_NO_CONTEXT) { - eglDestroyContext(engine->display, engine->context); - } - if (engine->surface != EGL_NO_SURFACE) { - eglDestroySurface(engine->display, engine->surface); - } - eglTerminate(engine->display); - } - engine->animating = 0; - engine->display = EGL_NO_DISPLAY; - engine->context = EGL_NO_CONTEXT; - engine->surface = EGL_NO_SURFACE; -} - -/** -* Process the next input event. -*/ -static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) { - struct engine* engine = (struct engine*)app->userData; - if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { - engine->state.x = AMotionEvent_getX(event, 0); - engine->state.y = AMotionEvent_getY(event, 0); - return 1; - } - return 0; -} - -/** -* Process the next main command. -*/ -static void engine_handle_cmd(struct android_app* app, int32_t cmd) { - struct engine* engine = (struct engine*)app->userData; - switch (cmd) { - case APP_CMD_SAVE_STATE: - // The system has asked us to save our current state. Do so. - engine->app->savedState = malloc(sizeof(struct saved_state)); - *((struct saved_state*)engine->app->savedState) = engine->state; - engine->app->savedStateSize = sizeof(struct saved_state); - break; - case APP_CMD_INIT_WINDOW: - // The window is being shown, get it ready. - if (engine->app->window != NULL) { - engine_init_display(engine); - engine_draw_frame(engine); - } - break; - case APP_CMD_TERM_WINDOW: - // The window is being hidden or closed, clean it up. - engine_term_display(engine); - break; - case APP_CMD_GAINED_FOCUS: - // When our app gains focus, we start monitoring the accelerometer. - if (engine->accelerometerSensor != NULL) { - ASensorEventQueue_enableSensor(engine->sensorEventQueue, - engine->accelerometerSensor); - // We'd like to get 60 events per second (in us). - ASensorEventQueue_setEventRate(engine->sensorEventQueue, - engine->accelerometerSensor, (1000L / 60) * 1000); - } - break; - case APP_CMD_LOST_FOCUS: - // When our app loses focus, we stop monitoring the accelerometer. - // This is to avoid consuming battery while not being used. - if (engine->accelerometerSensor != NULL) { - ASensorEventQueue_disableSensor(engine->sensorEventQueue, - engine->accelerometerSensor); - } - // Also stop animating. - engine->animating = 0; - engine_draw_frame(engine); - break; - } -} - -#include -#include -#include -#include -#include -#include -#include "unittestpp.h" -#include "src/TestReporter.h" -#include "src/TestDetails.h" -#include -#include -#include - -void printLn(const std::string& s) { - __android_log_print(ANDROID_LOG_WARN, "UnitTestpp", "%s", s.c_str()); -} - -struct MyTestReporter : UnitTest::TestReporter { - UNITTEST_LINKAGE virtual void ReportTestStart(UnitTest::TestDetails const& test) { - std::stringstream ss; - ss << test.suiteName << ":" << test.testName << ": Start."; - printLn(ss.str()); - } - UNITTEST_LINKAGE virtual void ReportFailure(UnitTest::TestDetails const& test, char const* failure) { - std::stringstream ss; - ss << test.suiteName << ":" << test.testName << ": " << failure; - printLn(ss.str()); - } - UNITTEST_LINKAGE virtual void ReportTestFinish(UnitTest::TestDetails const& test, bool passed, float secondsElapsed) { - if (!passed) { - std::stringstream ss; - ss << test.suiteName << ":" << test.testName << ": Failed. Seconds: " << secondsElapsed; - printLn(ss.str()); - } - } - UNITTEST_LINKAGE virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed) { - std::stringstream ss; - ss << "Tests complete. Total: " << totalTestCount << ", Failed: " << failedTestCount << ", Time: " << secondsElapsed; - printLn(ss.str()); - // Print a bunch of messages to defeat any batching that may be applied by adb or logcat - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - printLn("--- Flush buffer ---"); - } - UNITTEST_LINKAGE virtual void print(const std::string& s) { - printLn(s); - } -}; - -static std::string to_lower(const std::string &str) -{ - std::string lower; - for (auto iter = str.begin(); iter != str.end(); ++iter) - { - lower.push_back((char)tolower(*iter)); - } - return lower; -} - -bool matched_properties(UnitTest::TestProperties const& test_props) { - if (test_props.Has("Requires")) { - std::string const requires = test_props.Get("Requires"); - std::vector requirements; - - // Can be multiple requirements, a semi colon seperated list - std::string::size_type pos = requires.find_first_of(';'); - std::string::size_type last_pos = 0; - while (pos != std::string::npos) - { - requirements.push_back(requires.substr(last_pos, pos - last_pos)); - last_pos = pos + 1; - pos = requires.find_first_of(';', last_pos); - } - requirements.push_back(requires.substr(last_pos)); - for (auto iter = requirements.begin(); iter != requirements.end(); ++iter) - { - if (!UnitTest::GlobalSettings::Has(to_lower(*iter))) - { - return false; - } - } - } - return true; -} - -bool should_run_test(UnitTest::Test *pTest) -{ - if (pTest->m_properties.Has("Ignore")) return false; - if (pTest->m_properties.Has("Ignore:Linux")) return false; - if (pTest->m_properties.Has("Ignore:Android")) return false; - if (matched_properties(pTest->m_properties)) { - return true; - } - return false; -} - -void* RunTests() { - UnitTest::TestList& tests = UnitTest::GetTestList(); - - MyTestReporter mtr; - - // Do work - UnitTest::TestRunner testrunner(mtr, false); - testrunner.RunTestsIf(tests, - [](UnitTest::Test *pTest) -> bool - { - if (should_run_test(pTest)) - return true; - auto& test = pTest->m_details; - std::stringstream ss; - ss << test.suiteName << ":" << test.testName << ": Skipped."; - printLn(ss.str()); - return false; - }, 0); - - return nullptr; -} - -/** -* This is the main entry point of a native application that is using -* android_native_app_glue. It runs in its own thread, with its own -* event loop for receiving input events and doing other things. -*/ -void android_main(struct android_app* state) { - struct engine engine; - - cpprest_init(state->activity->vm); - - // Begin change path to temp dir - jobject nAct = state->activity->clazz; - auto env = crossplat::get_jvm_env(); - - auto contextClass = env->FindClass("android/content/Context"); - auto getCacheDir = env->GetMethodID(contextClass, "getCacheDir", "()Ljava/io/File;"); - - auto fileClass = env->FindClass("java/io/File"); - auto getPath = env->GetMethodID(fileClass, "getPath", "()Ljava/lang/String;"); - - auto cacheDir = env->CallObjectMethod(nAct, getCacheDir); - jstring cacheDirPath = (jstring)env->CallObjectMethod(cacheDir, getPath); - auto st = env->GetStringUTFChars(cacheDirPath, nullptr); - chdir(st); - env->ReleaseStringUTFChars(cacheDirPath, st); - // End change path to temp dir - - RunTests(); - - memset(&engine, 0, sizeof(engine)); - state->userData = &engine; - state->onAppCmd = engine_handle_cmd; - state->onInputEvent = engine_handle_input; - engine.app = state; - - // Prepare to monitor accelerometer - engine.sensorManager = ASensorManager_getInstance(); - engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager, - ASENSOR_TYPE_ACCELEROMETER); - engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager, - state->looper, LOOPER_ID_USER, NULL, NULL); - - if (state->savedState != NULL) { - // We are starting with a previous saved state; restore from it. - engine.state = *(struct saved_state*)state->savedState; - } - - engine.animating = 1; - - // loop waiting for stuff to do. - - while (1) { - // Read all pending events. - int ident; - int events; - struct android_poll_source* source; - - // If not animating, we will block forever waiting for events. - // If animating, we loop until all events are read, then continue - // to draw the next frame of animation. - while ((ident = ALooper_pollAll(engine.animating ? 0 : -1, NULL, &events, - (void**)&source)) >= 0) { - - // Process this event. - if (source != NULL) { - source->process(state, source); - } - - // Check if we are exiting. - if (state->destroyRequested != 0) { - engine_term_display(&engine); - return; - } - } - - if (engine.animating) { - // Done with events; draw next animation frame. - engine.state.angle += .01f; - if (engine.state.angle > 1) { - engine.state.angle = 0; - } - - // Drawing is throttled to the screen update rate, so there - // is no need to do timing here. - engine_draw_frame(&engine); - } - } -} diff --git a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/packages.config b/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/packages.config deleted file mode 100644 index c99b35a84e..0000000000 --- a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/packages.config +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/pch.h b/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/pch.h deleted file mode 100644 index 5bf4b11366..0000000000 --- a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.NativeActivity/pch.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// pch.h -// Header for standard system include files. -// -// Used by the build system to generate the precompiled header. Note that no -// pch.cpp is needed and the pch.h is automatically included in all cpp files -// that are part of the project -// - -#include -#include - -#include -#include -#include - -#include -#include - -#include - -#include -#include "android_native_app_glue.h" diff --git a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/AndroidManifest.xml b/Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/AndroidManifest.xml deleted file mode 100644 index 711b77cda6..0000000000 --- a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/AndroidManifest.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/TestRunner.android.Packaging.androidproj b/Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/TestRunner.android.Packaging.androidproj deleted file mode 100644 index d4e2b5fcc6..0000000000 --- a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/TestRunner.android.Packaging.androidproj +++ /dev/null @@ -1,84 +0,0 @@ - - - - - Debug - ARM - - - Release - ARM - - - Debug - x86 - - - Release - x86 - - - - TestRunner_android - 14.0 - 1.0 - {7cf3c460-3486-4106-80cd-eb802dfef373} - - - - true - - - false - - - true - - - false - - - - - - - - TestRunner_android - - - - - TestRunner_android - - - - - TestRunner_android - - - - - TestRunner_android - - - - - - - - - - - - {d1060d0a-a10e-444d-9f6b-9676ea453f9a} - - - - - - - - - - - diff --git a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/build.xml b/Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/build.xml deleted file mode 100644 index 3b9c329d4a..0000000000 --- a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/build.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/project.properties b/Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/project.properties deleted file mode 100644 index e613b43798..0000000000 --- a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/project.properties +++ /dev/null @@ -1,2 +0,0 @@ -# Project target -target=$(androidapilevel) diff --git a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/res/values/strings.xml b/Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/res/values/strings.xml deleted file mode 100644 index 31108df64d..0000000000 --- a/Release/tests/common/TestRunner/vs14.android/TestRunner.android.Packaging/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - TestRunner.android.Packaging - diff --git a/Release/tests/common/TestRunner/vs14.uwp/TestRunner140.uwp.vcxproj b/Release/tests/common/TestRunner/vs14.uwp/TestRunner140.uwp.vcxproj deleted file mode 100644 index 231344b499..0000000000 --- a/Release/tests/common/TestRunner/vs14.uwp/TestRunner140.uwp.vcxproj +++ /dev/null @@ -1,118 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {5E421824-72D7-4482-A161-8D7D02308E52} - Win32Proj - SAK - SAK - SAK - SAK - 14.0 - v140 - Unicode - Application - - - - true - - - false - true - - - false - true - - - false - true - - - - - - - - - - - TestRunner.winrt - - - - - NotUsing - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - WINRT_TEST_RUNNER;WIN32;_CONSOLE;%(PreprocessorDefinitions) - false - - - Console - $(OutDir);%(AdditionalLibraryDirectories) - true - - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - - - - - - - - - - - - - {04214181-57D7-45F5-8499-1A5530CE6CBF} - - - - - - diff --git a/Release/tests/common/TestRunner/vs14.uwp/TestRunner140.uwp.vcxproj.filters b/Release/tests/common/TestRunner/vs14.uwp/TestRunner140.uwp.vcxproj.filters deleted file mode 100644 index f9fa6c25ca..0000000000 --- a/Release/tests/common/TestRunner/vs14.uwp/TestRunner140.uwp.vcxproj.filters +++ /dev/null @@ -1,24 +0,0 @@ - - - - - Source Files - - - Source Files - - - - - {5e4d32c8-a472-4388-b880-920a7a546fa3} - - - {f05a925c-282c-4424-ae9a-10fe7f88fe47} - - - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/common/TestRunner/vs14/TestRunner140.vcxproj b/Release/tests/common/TestRunner/vs14/TestRunner140.vcxproj deleted file mode 100644 index e14b9ab7e0..0000000000 --- a/Release/tests/common/TestRunner/vs14/TestRunner140.vcxproj +++ /dev/null @@ -1,248 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {6490C580-DD4A-4F2D-A345-732C5148349F} - Win32Proj - TestRunner - $(VCTargetsPath12) - SAK - SAK - SAK - SAK - - - - Application - true - Unicode - v140 - - - Application - true - Unicode - v140 - - - Application - true - Unicode - v140 - - - Application - false - true - Unicode - v140 - - - Application - false - true - Unicode - v140 - - - Application - false - true - Unicode - v140 - - - - - - - - - - - - - - - - - - - - - - - TestRunner - - - TestRunner - - - TestRunner - - - false - TestRunner - - - false - TestRunner - - - false - TestRunner - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - NotUsing - Disabled - DESKTOP_TEST_RUNNER;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - NotUsing - Disabled - DESKTOP_TEST_RUNNER;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - NotUsing - Disabled - DESKTOP_TEST_RUNNER;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - NotUsing - MaxSpeed - true - true - DESKTOP_TEST_RUNNER;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - NotUsing - MaxSpeed - true - true - DESKTOP_TEST_RUNNER;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - NotUsing - MaxSpeed - true - true - DESKTOP_TEST_RUNNER;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - $(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - false - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - {3eb86c0d-432c-4ffc-bad4-8df4efc7d0ff} - - - - - - \ No newline at end of file diff --git a/Release/tests/common/TestRunner/vs14/TestRunner140.vcxproj.filters b/Release/tests/common/TestRunner/vs14/TestRunner140.vcxproj.filters deleted file mode 100644 index f9fa6c25ca..0000000000 --- a/Release/tests/common/TestRunner/vs14/TestRunner140.vcxproj.filters +++ /dev/null @@ -1,24 +0,0 @@ - - - - - Source Files - - - Source Files - - - - - {5e4d32c8-a472-4388-b880-920a7a546fa3} - - - {f05a925c-282c-4424-ae9a-10fe7f88fe47} - - - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/common/UnitTestpp/vs14.android/UnitTestpp140.android.vcxproj b/Release/tests/common/UnitTestpp/vs14.android/UnitTestpp140.android.vcxproj deleted file mode 100644 index c7b52f072b..0000000000 --- a/Release/tests/common/UnitTestpp/vs14.android/UnitTestpp140.android.vcxproj +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - Debug - ARM - - - Debug - x86 - - - Release - ARM - - - Release - x86 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - - - - - {afb49019-965b-4c10-baff-c86c16d58010} - false - false - false - false - false - - - - {3EFD8540-A54D-4900-887E-F856162535A0} - Android - Android - 2.0 - UnitTestpp140.android - - - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - - - - 378b82c3 - - - - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Enabled - c++11 - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - d - - - UnitTestpp140.android - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - diff --git a/Release/tests/common/UnitTestpp/vs14.android/UnitTestpp140.android.vcxproj.filters b/Release/tests/common/UnitTestpp/vs14.android/UnitTestpp140.android.vcxproj.filters deleted file mode 100644 index eccc1b629f..0000000000 --- a/Release/tests/common/UnitTestpp/vs14.android/UnitTestpp140.android.vcxproj.filters +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - - - {99f8e13d-e0d8-4917-83d5-6658b4a57e8e} - - - {40c405e2-9304-484c-b23b-441e611abff6} - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/tests/common/UnitTestpp/vs14.uwp/UnitTestpp140.uwp.vcxproj b/Release/tests/common/UnitTestpp/vs14.uwp/UnitTestpp140.uwp.vcxproj deleted file mode 100644 index 01a4ef1b5d..0000000000 --- a/Release/tests/common/UnitTestpp/vs14.uwp/UnitTestpp140.uwp.vcxproj +++ /dev/null @@ -1,208 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {04214181-57D7-45F5-8499-1A5530CE6CBF} - Win32Proj - UnitTest - SAK - SAK - SAK - SAK - 14.0 - Windows Store - 10.0.10240.0 - 10.0.10240.0 - 10.0 - - - - DynamicLibrary - Unicode - v140 - - - true - - - false - true - - - - - - $(CasablancaIncludeDir);$(TestRoot)\Common\UnitTestpp\src\;%(AdditionalIncludeDirectories); - NotUsing - UNITTEST_DLL_EXPORT;WIN32;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - $(WindowsSdkDir)\UnionMetadata;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - true - false - stdafx.h - - - Windows - true - true - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - $(VCINSTALLDIR)\lib\store;%(AdditionalLibraryDirectories); - ucrtd.lib;vcruntimed.lib;vccorlibd.lib;msvcrtd.lib;msvcprtd.lib;RuntimeObject.lib;%(AdditionalDependencies) - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - $(VCINSTALLDIR)\lib\store\arm;%(AdditionalLibraryDirectories); - ucrtd.lib;vcruntimed.lib;vccorlibd.lib;uuid.lib;ole32.lib;msvcrtd.lib;msvcprtd.lib;RuntimeObject.lib;%(AdditionalDependencies) - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - $(VCINSTALLDIR)\lib\store\amd64;%(AdditionalLibraryDirectories); - ucrtd.lib;vcruntimed.lib;vccorlibd.lib;msvcrtd.lib;msvcprtd.lib;RuntimeObject.lib;%(AdditionalDependencies) - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - $(VCINSTALLDIR)\lib\store;%(AdditionalLibraryDirectories); - ucrt.lib;vcruntime.lib;vccorlib.lib;msvcrt.lib;msvcprt.lib;RuntimeObject.lib;%(AdditionalDependencies) - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - $(VCINSTALLDIR)\lib\store\arm;%(AdditionalLibraryDirectories); - ucrt.lib;vcruntime.lib;vccorlib.lib;uuid.lib;ole32.lib;msvcrt.lib;msvcprt.lib;RuntimeObject.lib;%(AdditionalDependencies) - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - $(VCINSTALLDIR)\lib\store\amd64;%(AdditionalLibraryDirectories); - ucrt.lib;vcruntime.lib;vccorlib.lib;msvcrt.lib;msvcprt.lib;RuntimeObject.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/common/UnitTestpp/vs14.uwp/UnitTestpp140.uwp.vcxproj.filters b/Release/tests/common/UnitTestpp/vs14.uwp/UnitTestpp140.uwp.vcxproj.filters deleted file mode 100644 index 6fd73f9e3b..0000000000 --- a/Release/tests/common/UnitTestpp/vs14.uwp/UnitTestpp140.uwp.vcxproj.filters +++ /dev/null @@ -1,159 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - {640fb93d-0deb-4bc4-a035-5d44d5c2af4b} - - - {b883825b-c6c4-4545-806e-dfe105753ac8} - - - \ No newline at end of file diff --git a/Release/tests/common/UnitTestpp/vs14/TestUnitTestpp140.vcxproj b/Release/tests/common/UnitTestpp/vs14/TestUnitTestpp140.vcxproj deleted file mode 100644 index b1ccc17621..0000000000 --- a/Release/tests/common/UnitTestpp/vs14/TestUnitTestpp140.vcxproj +++ /dev/null @@ -1,202 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {E715BBE6-743D-47C2-8F43-92AA18F6ED19} - Win32Proj - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - TestUnitTestpp140 - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - $(CasablancaIncludeDir);%(AdditionalIncludeDirectories); - - - - - NotUsing - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - - - - - NotUsing - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - - - - - NotUsing - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - - - - - MaxSpeed - NotUsing - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - MaxSpeed - NotUsing - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - MaxSpeed - NotUsing - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - - - - \ No newline at end of file diff --git a/Release/tests/common/UnitTestpp/vs14/TestUnitTestpp140.vcxproj.filters b/Release/tests/common/UnitTestpp/vs14/TestUnitTestpp140.vcxproj.filters deleted file mode 100644 index 44e0743ad6..0000000000 --- a/Release/tests/common/UnitTestpp/vs14/TestUnitTestpp140.vcxproj.filters +++ /dev/null @@ -1,72 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - {420b7d9f-7900-40f3-8aa7-3c800278bc98} - - - {7ddca59d-156c-46f2-af93-4a03f915bbcb} - - - \ No newline at end of file diff --git a/Release/tests/common/UnitTestpp/vs14/UnitTestpp140.vcxproj b/Release/tests/common/UnitTestpp/vs14/UnitTestpp140.vcxproj deleted file mode 100644 index 3bd4978222..0000000000 --- a/Release/tests/common/UnitTestpp/vs14/UnitTestpp140.vcxproj +++ /dev/null @@ -1,228 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - Win32Proj - UnitTest - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - UnitTestpp140 - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - $(CasablancaIncludeDir);$(TestRoot)\Common\UnitTestpp\src\;%(AdditionalIncludeDirectories); - Use - - - - - NotUsing - Disabled - UNITTEST_DLL_EXPORT;WIN32;_DEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - - - - - NotUsing - Disabled - UNITTEST_DLL_EXPORT;WIN32;_DEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - - - - - NotUsing - Disabled - UNITTEST_DLL_EXPORT;WIN32;_DEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - - - - - MaxSpeed - NotUsing - true - true - UNITTEST_DLL_EXPORT;WIN32;NDEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - MaxSpeed - NotUsing - true - true - UNITTEST_DLL_EXPORT;WIN32;NDEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - MaxSpeed - NotUsing - true - true - UNITTEST_DLL_EXPORT;WIN32;NDEBUG;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - - - Windows - true - true - true - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/common/UnitTestpp/vs14/UnitTestpp140.vcxproj.filters b/Release/tests/common/UnitTestpp/vs14/UnitTestpp140.vcxproj.filters deleted file mode 100644 index 6fd73f9e3b..0000000000 --- a/Release/tests/common/UnitTestpp/vs14/UnitTestpp140.vcxproj.filters +++ /dev/null @@ -1,159 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - {640fb93d-0deb-4bc4-a035-5d44d5c2af4b} - - - {b883825b-c6c4-4545-806e-dfe105753ac8} - - - \ No newline at end of file diff --git a/Release/tests/common/utilities/CMakeLists.txt b/Release/tests/common/utilities/CMakeLists.txt index dfe4852da6..a2d2306577 100644 --- a/Release/tests/common/utilities/CMakeLists.txt +++ b/Release/tests/common/utilities/CMakeLists.txt @@ -6,7 +6,6 @@ endif() add_library(common_utilities os_utilities.cpp - stdafx.cpp ) if(NOT BUILD_SHARED_LIBS) diff --git a/Release/tests/common/utilities/os_utilities.cpp b/Release/tests/common/utilities/os_utilities.cpp index 639460078e..0e318e8069 100644 --- a/Release/tests/common/utilities/os_utilities.cpp +++ b/Release/tests/common/utilities/os_utilities.cpp @@ -4,17 +4,17 @@ * * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * -* os_utilities.cpp - defines an abstraction for common OS functions like Sleep, hiding the underlying platform. +* os_utilities.cpp - defines an abstraction for common OS functions like Sleep, hiding the underlying platform. * * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ -#include "stdafx.h" - #include "os_utilities.h" #ifdef WIN32 +#define NOMINMAX #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#include #include #else #include @@ -54,4 +54,3 @@ long os_utilities::interlocked_exchange(volatile long *target, long value) } }}} - diff --git a/Release/tests/common/utilities/stdafx.cpp b/Release/tests/common/utilities/stdafx.cpp deleted file mode 100644 index b5b248455b..0000000000 --- a/Release/tests/common/utilities/stdafx.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.cpp -* -* Pre-compiled headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ - -// stdafx.cpp : source file that includes just the standard includes -// Server.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" diff --git a/Release/tests/common/utilities/stdafx.h b/Release/tests/common/utilities/stdafx.h deleted file mode 100644 index db5203bed7..0000000000 --- a/Release/tests/common/utilities/stdafx.h +++ /dev/null @@ -1,24 +0,0 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* stdafx.h -* -* Pre-compiled headers -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ - -#pragma once - -#ifdef WIN32 - -#include "targetver.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define NOMINMAX -#include - -#endif diff --git a/Release/tests/common/utilities/targetver.h b/Release/tests/common/utilities/targetver.h deleted file mode 100644 index 95417e6073..0000000000 --- a/Release/tests/common/utilities/targetver.h +++ /dev/null @@ -1,20 +0,0 @@ -/*** -* Copyright (C) Microsoft. All rights reserved. -* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. -* -* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -* -* targetver.h -* -* Standard VS-generated header file. -* -* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -****/ -#pragma once - -// Including SDKDDKVer.h defines the highest available Windows platform. - -// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and -// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. - -#include diff --git a/Release/tests/common/utilities/vs14.android/CommonUtilities140.android.vcxproj b/Release/tests/common/utilities/vs14.android/CommonUtilities140.android.vcxproj deleted file mode 100644 index 53592625d0..0000000000 --- a/Release/tests/common/utilities/vs14.android/CommonUtilities140.android.vcxproj +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - Debug - ARM - - - Debug - x86 - - - Release - ARM - - - Release - x86 - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - {3efd8540-a54d-4900-887e-f856162535a0} - - - - {7C4E6E33-42E2-4472-9319-DDE7564F3DAE} - Android - Android - 2.0 - CommonUtilities140.android - - - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - - - - 378b82c3 - - - - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Enabled - c++11 - true - true - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - - - - d - - - CommonUtilities140.android - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - diff --git a/Release/tests/common/utilities/vs14.android/CommonUtilities140.android.vcxproj.filters b/Release/tests/common/utilities/vs14.android/CommonUtilities140.android.vcxproj.filters deleted file mode 100644 index 65f1bbe659..0000000000 --- a/Release/tests/common/utilities/vs14.android/CommonUtilities140.android.vcxproj.filters +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - {31a9e4f4-e463-4a16-afeb-4e08578514f0} - - - {0354a1e4-1028-4f71-ae58-465027fa590d} - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/tests/common/utilities/vs14.uwp/CommonUtilities140.uwp.vcxproj b/Release/tests/common/utilities/vs14.uwp/CommonUtilities140.uwp.vcxproj deleted file mode 100644 index 10b6ac1e01..0000000000 --- a/Release/tests/common/utilities/vs14.uwp/CommonUtilities140.uwp.vcxproj +++ /dev/null @@ -1,167 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {DA089EAD-00A2-43CF-9954-DF01E8ED5E94} - Win32Proj - CommonUtilities140 - SAK - SAK - SAK - SAK - en-US - 14.0 - 10.0.10240.0 - 10.0.10240.0 - Unicode - v140 - DynamicLibrary - true - - - - true - - - false - true - - - - - - - Use - WIN32;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - true - false - stdafx.h - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories); - - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - {04214181-57D7-45F5-8499-1A5530CE6CBF} - - - {5E421824-72D7-4482-A161-8D7D02308E52} - - - {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Release/tests/common/utilities/vs14.uwp/CommonUtilities140.uwp.vcxproj.filters b/Release/tests/common/utilities/vs14.uwp/CommonUtilities140.uwp.vcxproj.filters deleted file mode 100644 index 1325242b47..0000000000 --- a/Release/tests/common/utilities/vs14.uwp/CommonUtilities140.uwp.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - {24e13f0e-e0f6-4fe0-922a-5cf7cbe823f4} - - - {ef18a939-f1a3-4e9e-b93a-05826fbae7f6} - - - \ No newline at end of file diff --git a/Release/tests/common/utilities/vs14.xp/CommonUtilities140.xp.vcxproj b/Release/tests/common/utilities/vs14.xp/CommonUtilities140.xp.vcxproj deleted file mode 100644 index 202e5daf98..0000000000 --- a/Release/tests/common/utilities/vs14.xp/CommonUtilities140.xp.vcxproj +++ /dev/null @@ -1,150 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {5AD81270-B089-4E1B-8741-6486F39DE273} - Win32Proj - CommonUtilities140 - SAK - SAK - SAK - SAK - $(VCTargetsPath14) - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - Create - Create - Create - Create - - - - - - - - - - - {75885703-7f3d-4086-8e60-c60b9b126f7e} - - - {6490c580-dd4a-4f2d-a345-732c5148349f} - - - {3eb86c0d-432c-4ffc-bad4-8df4efc7d0ff} - - - - - - \ No newline at end of file diff --git a/Release/tests/common/utilities/vs14/CommonUtilities140.vcxproj b/Release/tests/common/utilities/vs14/CommonUtilities140.vcxproj deleted file mode 100644 index c5a179f24c..0000000000 --- a/Release/tests/common/utilities/vs14/CommonUtilities140.vcxproj +++ /dev/null @@ -1,200 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - Win32Proj - CommonUtilities120 - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - Advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - Advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONUTILITIES_EXPORTS;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - {3eb86c0d-432c-4ffc-bad4-8df4efc7d0ff} - - - - - - \ No newline at end of file diff --git a/Release/tests/common/utilities/vs14/CommonUtilities140.vcxproj.filters b/Release/tests/common/utilities/vs14/CommonUtilities140.vcxproj.filters deleted file mode 100644 index 1325242b47..0000000000 --- a/Release/tests/common/utilities/vs14/CommonUtilities140.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - {24e13f0e-e0f6-4fe0-922a-5cf7cbe823f4} - - - {ef18a939-f1a3-4e9e-b93a-05826fbae7f6} - - - \ No newline at end of file diff --git a/Release/tests/functional/http/client/CMakeLists.txt b/Release/tests/functional/http/client/CMakeLists.txt index 17cf4eff81..d92b477481 100644 --- a/Release/tests/functional/http/client/CMakeLists.txt +++ b/Release/tests/functional/http/client/CMakeLists.txt @@ -22,7 +22,6 @@ set(SOURCES to_string_tests.cpp http_client_fuzz_tests.cpp compression_tests.cpp - stdafx.cpp ) add_casablanca_test(httpclient_test SOURCES) @@ -32,6 +31,19 @@ else() target_link_libraries(httpclient_test PRIVATE httptest_utilities) endif() +if(MSVC) + get_target_property(_srcs httpclient_test SOURCES) + + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") + set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/client-tests-stdafx.pch") + set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/client-tests-stdafx.pch") + endif() + + set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h /Fpclient-tests-stdafx.pch") + target_sources(httpclient_test PRIVATE stdafx.cpp) + target_compile_options(httpclient_test PRIVATE /Yustdafx.h /Fpclient-tests-stdafx.pch) +endif() + if(NOT WIN32) cpprest_find_boost() target_link_libraries(httpclient_test PRIVATE cpprestsdk_boost_internal) diff --git a/Release/tests/functional/http/client/compression_tests.cpp b/Release/tests/functional/http/client/compression_tests.cpp index fd9142931a..889ab71797 100644 --- a/Release/tests/functional/http/client/compression_tests.cpp +++ b/Release/tests/functional/http/client/compression_tests.cpp @@ -11,10 +11,11 @@ * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ +#include "stdafx.h" + #include "cpprest/details/http_helpers.h" #include "cpprest/version.h" #include "cpprest/asyncrt_utils.h" -#include "stdafx.h" #include #ifndef __cplusplus_winrt diff --git a/Release/tests/functional/http/client/vs14.android/HttpClient140_test.android.vcxproj b/Release/tests/functional/http/client/vs14.android/HttpClient140_test.android.vcxproj deleted file mode 100644 index 9d4978a9af..0000000000 --- a/Release/tests/functional/http/client/vs14.android/HttpClient140_test.android.vcxproj +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - Debug - ARM - - - Debug - x86 - - - Release - ARM - - - Release - x86 - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - - {b444ee47-1340-4a74-820d-cdd55f9f22f7} - - - - {0EE481DA-A97F-4831-9119-C65EB2D7B4DA} - Android - Android - 2.0 - HttpClient140_test.android - - - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - - - - 378b82c3 - - - - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Enabled - c++11 - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - d - - - HttpClient140_test.android - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - diff --git a/Release/tests/functional/http/client/vs14.android/HttpClient140_test.android.vcxproj.filters b/Release/tests/functional/http/client/vs14.android/HttpClient140_test.android.vcxproj.filters deleted file mode 100644 index 832cc001c1..0000000000 --- a/Release/tests/functional/http/client/vs14.android/HttpClient140_test.android.vcxproj.filters +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - {2102c5c5-ec68-4b17-a463-475af72c31aa} - - - {2e4123cf-9aa6-4269-93d6-4a24f7eb2af0} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/functional/http/client/vs14.android/packages.config b/Release/tests/functional/http/client/vs14.android/packages.config deleted file mode 100644 index 4bd0fd80ad..0000000000 --- a/Release/tests/functional/http/client/vs14.android/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/Release/tests/functional/http/client/vs14.uwp/HttpClient140_test.uwp.vcxproj b/Release/tests/functional/http/client/vs14.uwp/HttpClient140_test.uwp.vcxproj deleted file mode 100644 index 704e677f5a..0000000000 --- a/Release/tests/functional/http/client/vs14.uwp/HttpClient140_test.uwp.vcxproj +++ /dev/null @@ -1,153 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {E1E5C85C-9C98-49FC-A645-C1368E981940} - HttpTests - SAK - SAK - SAK - SAK - en-US - Windows Store - 14.0 - true - Unicode - v140 - DynamicLibrary - 10.0.10240.0 - 10.0.10240.0 - - - - true - - - false - true - - - - - - - Use - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\..\utilities\include;%(AdditionalIncludeDirectories) - WIN32;_USRDLL;%(PreprocessorDefinitions) - true - false - stdafx.h - -Zm350 /bigobj%(AdditionalOptions) - - - Windows - true - CommonUtilities140.uwp.lib;%(AdditionalDependencies) - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - - - - - {039BA657-296A-4E11-8E37-948A5919F0B8} - - - {DA089EAD-00A2-43CF-9954-DF01E8ED5E94} - - - {04214181-57D7-45F5-8499-1A5530CE6CBF} - - - {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - - - diff --git a/Release/tests/functional/http/client/vs14.uwp/HttpClient140_test.uwp.vcxproj.filters b/Release/tests/functional/http/client/vs14.uwp/HttpClient140_test.uwp.vcxproj.filters deleted file mode 100644 index a8536ce996..0000000000 --- a/Release/tests/functional/http/client/vs14.uwp/HttpClient140_test.uwp.vcxproj.filters +++ /dev/null @@ -1,87 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - - - {fadb7f38-3d0c-4a31-af39-6364be0d9793} - - - {ee68ca67-bbcf-4196-89c7-fbf59083ac16} - - - \ No newline at end of file diff --git a/Release/tests/functional/http/client/vs14/HttpClient140_test.vcxproj b/Release/tests/functional/http/client/vs14/HttpClient140_test.vcxproj deleted file mode 100644 index 691f035901..0000000000 --- a/Release/tests/functional/http/client/vs14/HttpClient140_test.vcxproj +++ /dev/null @@ -1,240 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {dc215f97-c43c-47f5-9784-711908a24ae3} - HttpTests - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\..\utilities\include;%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - -Zm350 /bigobj%(AdditionalOptions) - StdCall - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;httpapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - -Zm350 /bigobj%(AdditionalOptions) - StdCall - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;httpapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - -Zm350 /bigobj %(AdditionalOptions) - StdCall - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;httpapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - -Zm350 /bigobj%(AdditionalOptions) - StdCall - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;httpapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - -Zm350 /bigobj%(AdditionalOptions) - StdCall - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;httpapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - -Zm350 /bigobj%(AdditionalOptions) - StdCall - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;httpapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {6837625b-c0db-4fd0-aee2-19699031b76e} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/http/client/vs14/HttpClient140_test.vcxproj.filters b/Release/tests/functional/http/client/vs14/HttpClient140_test.vcxproj.filters deleted file mode 100644 index 6a577a5662..0000000000 --- a/Release/tests/functional/http/client/vs14/HttpClient140_test.vcxproj.filters +++ /dev/null @@ -1,88 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - Source Files - - - - - Header Files - - - Header Files - - - - - {fadb7f38-3d0c-4a31-af39-6364be0d9793} - - - {ee68ca67-bbcf-4196-89c7-fbf59083ac16} - - - \ No newline at end of file diff --git a/Release/tests/functional/http/listener/CMakeLists.txt b/Release/tests/functional/http/listener/CMakeLists.txt index 33be6fb354..aa4245fed8 100644 --- a/Release/tests/functional/http/listener/CMakeLists.txt +++ b/Release/tests/functional/http/listener/CMakeLists.txt @@ -13,7 +13,6 @@ if(NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) response_stream_tests.cpp status_code_reason_phrase_tests.cpp to_string_tests.cpp - stdafx.cpp ) add_casablanca_test(httplistener_test SOURCES) @@ -22,4 +21,15 @@ if(NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) else() target_link_libraries(httplistener_test PRIVATE httptest_utilities) endif() + + if(MSVC) + get_target_property(_srcs httplistener_test SOURCES) + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") + set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/listener-tests-stdafx.pch") + set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/listener-tests-stdafx.pch") + endif() + set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h /Fplistener-tests-stdafx.pch") + target_sources(httplistener_test PRIVATE stdafx.cpp) + target_compile_options(httplistener_test PRIVATE /Yustdafx.h /Fplistener-tests-stdafx.pch) + endif() endif() diff --git a/Release/tests/functional/http/listener/vs14.android/HttpListener140_test.android.vcxproj b/Release/tests/functional/http/listener/vs14.android/HttpListener140_test.android.vcxproj deleted file mode 100644 index 2bb8421046..0000000000 --- a/Release/tests/functional/http/listener/vs14.android/HttpListener140_test.android.vcxproj +++ /dev/null @@ -1,160 +0,0 @@ - - - - - - Debug - ARM - - - Debug - x86 - - - Release - ARM - - - Release - x86 - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - {b444ee47-1340-4a74-820d-cdd55f9f22f7} - - - - {2B00D1C0-1A93-4A32-8932-C3CC43ACFF45} - Android - Android - 2.0 - HttpListener140_test.android - - - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - - - - 378b82c3 - - - - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Enabled - c++11 - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - d - - - HttpListener140_test.android - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - diff --git a/Release/tests/functional/http/listener/vs14.android/HttpListener140_test.android.vcxproj.filters b/Release/tests/functional/http/listener/vs14.android/HttpListener140_test.android.vcxproj.filters deleted file mode 100644 index 48553613bc..0000000000 --- a/Release/tests/functional/http/listener/vs14.android/HttpListener140_test.android.vcxproj.filters +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - {fa079c21-f36e-4713-a05c-fced62c90650} - - - {c62749db-a977-4b3f-abe9-839f3f8a21b4} - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/tests/functional/http/listener/vs14/HttpListener140_test.vcxproj b/Release/tests/functional/http/listener/vs14/HttpListener140_test.vcxproj deleted file mode 100644 index 23a5617b20..0000000000 --- a/Release/tests/functional/http/listener/vs14/HttpListener140_test.vcxproj +++ /dev/null @@ -1,242 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {2853ec0b-1b8e-4d9d-8436-4ef6dded5378} - HttpTests - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - - - - - - - - - - - - - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(TestRoot)\functional\http\utilities\include;%(AdditionalIncludeDirectories) - -Zm140 /bigobj%(AdditionalOptions) - FastCall - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(TestRoot)\functional\http\utilities\include;%(AdditionalIncludeDirectories) - -Zm140 /bigobj%(AdditionalOptions) - FastCall - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(TestRoot)\functional\http\utilities\include;%(AdditionalIncludeDirectories) - -Zm140 /bigobj%(AdditionalOptions) - FastCall - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(TestRoot)\functional\http\utilities\include;%(AdditionalIncludeDirectories) - -Zm140 /bigobj%(AdditionalOptions) - FastCall - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(TestRoot)\functional\http\utilities\include;%(AdditionalIncludeDirectories) - -Zm140 /bigobj%(AdditionalOptions) - FastCall - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(TestRoot)\functional\http\utilities\include;%(AdditionalIncludeDirectories) - -Zm140 /bigobj%(AdditionalOptions) - FastCall - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {6837625b-c0db-4fd0-aee2-19699031b76e} - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/http/listener/vs14/HttpListener140_test.vcxproj.filters b/Release/tests/functional/http/listener/vs14/HttpListener140_test.vcxproj.filters deleted file mode 100644 index 6041b38df7..0000000000 --- a/Release/tests/functional/http/listener/vs14/HttpListener140_test.vcxproj.filters +++ /dev/null @@ -1,63 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - - - {3de7d3df-7d70-4ea1-a460-bc378ed266c2} - - - {4ac74123-f940-4347-9a8e-d9e35ba7c7ac} - - - \ No newline at end of file diff --git a/Release/tests/functional/http/utilities/vs14.android/HttpTestUtilities140.android.vcxproj b/Release/tests/functional/http/utilities/vs14.android/HttpTestUtilities140.android.vcxproj deleted file mode 100644 index 62a0cf8a5a..0000000000 --- a/Release/tests/functional/http/utilities/vs14.android/HttpTestUtilities140.android.vcxproj +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - Debug - ARM - - - Debug - x86 - - - Release - ARM - - - Release - x86 - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - {7c4e6e33-42e2-4472-9319-dde7564f3dae} - - - - {B444EE47-1340-4A74-820D-CDD55F9F22F7} - Android - Android - 2.0 - HttpTestUtilities140.android - - - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - - - - 378b82c3 - - - - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Enabled - c++11 - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - d - - - HttpTestUtilities140.android - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - diff --git a/Release/tests/functional/http/utilities/vs14.android/HttpTestUtilities140.android.vcxproj.filters b/Release/tests/functional/http/utilities/vs14.android/HttpTestUtilities140.android.vcxproj.filters deleted file mode 100644 index cd9c4f61a3..0000000000 --- a/Release/tests/functional/http/utilities/vs14.android/HttpTestUtilities140.android.vcxproj.filters +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - {0bfc92ca-392b-4e84-86de-9f87dea20ad1} - - - {6fdd8038-3b97-4ab2-8b8d-0e15fc4dbfdc} - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/tests/functional/http/utilities/vs14.uwp/HttpTestUtilities140.uwp.vcxproj b/Release/tests/functional/http/utilities/vs14.uwp/HttpTestUtilities140.uwp.vcxproj deleted file mode 100644 index c5282c8210..0000000000 --- a/Release/tests/functional/http/utilities/vs14.uwp/HttpTestUtilities140.uwp.vcxproj +++ /dev/null @@ -1,183 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {039BA657-296A-4E11-8E37-948A5919F0B8} - SAK - SAK - SAK - SAK - Win32Proj - en-US - 14.0 - Unicode - v140 - DynamicLibrary - Windows Store - 10.0.10240.0 - 10.0.10240.0 - - - - true - - - false - true - - - - - - Use - WIN32;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\include - $(WindowsSdkDir)\UnionMetadata;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - -Zm200 %(AdditionalOptions) - true - false - stdafx.h - - - Windows - true - true - CommonUtilities140.uwp.lib;%(AdditionalDependencies) - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - $(VCINSTALLDIR)\lib\store;$(OutDir);%(AdditionalLibraryDirectories); - ucrtd.lib;vcruntimed.lib;vccorlibd.lib;msvcrtd.lib;msvcprtd.lib;concrtd.lib;Winhttp.lib;Httpapi.lib;RuntimeObject.lib;%(AdditionalDependencies) - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - $(VCINSTALLDIR)\lib\store\amd64;$(OutDir);%(AdditionalLibraryDirectories); - ucrtd.lib;vcruntimed.lib;vccorlibd.lib;msvcrtd.lib;msvcprtd.lib;concrtd.lib;Winhttp.lib;Httpapi.lib;RuntimeObject.lib;%(AdditionalDependencies) - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - $(VCINSTALLDIR)\lib\store\arm;$(OutDir);%(AdditionalLibraryDirectories); - ucrtd.lib;vcruntimed.lib;vccorlibd.lib;msvcrtd.lib;msvcprtd.lib;concrtd.lib;Winhttp.lib;Httpapi.lib;RuntimeObject.lib;%(AdditionalDependencies) - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - $(VCINSTALLDIR)\lib\store\arm;$(OutDir);%(AdditionalLibraryDirectories); - ucrt.lib;vcruntime.lib;vccorlib.lib;msvcrt.lib;msvcprt.lib;concrt.lib;Winhttp.lib;Httpapi.lib;RuntimeObject.lib;%(AdditionalDependencies) - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - $(VCINSTALLDIR)\lib\store;$(OutDir);%(AdditionalLibraryDirectories); - ucrt.lib;vcruntime.lib;vccorlib.lib;msvcrt.lib;msvcprt.lib;concrt.lib;Winhttp.lib;Httpapi.lib;RuntimeObject.lib;%(AdditionalDependencies) - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - $(VCINSTALLDIR)\lib\store\amd64;$(OutDir);%(AdditionalLibraryDirectories); - ucrt.lib;vcruntime.lib;vccorlib.lib;msvcrt.lib;msvcprt.lib;concrt.lib;Winhttp.lib;Httpapi.lib;RuntimeObject.lib;%(AdditionalDependencies) - - - - - {DA089EAD-00A2-43CF-9954-DF01E8ED5E94} - - - {04214181-57D7-45F5-8499-1A5530CE6CBF} - - - {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/http/utilities/vs14.uwp/HttpTestUtilities140.uwp.vcxproj.filters b/Release/tests/functional/http/utilities/vs14.uwp/HttpTestUtilities140.uwp.vcxproj.filters deleted file mode 100644 index c965e9cb22..0000000000 --- a/Release/tests/functional/http/utilities/vs14.uwp/HttpTestUtilities140.uwp.vcxproj.filters +++ /dev/null @@ -1,51 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - {96f6b99e-76ae-4ace-801c-39bb8d308125} - - - {d4ba757b-dfdc-4d61-a9bd-19e957c5a09c} - - - \ No newline at end of file diff --git a/Release/tests/functional/http/utilities/vs14/HttpTestUtilities140.vcxproj b/Release/tests/functional/http/utilities/vs14/HttpTestUtilities140.vcxproj deleted file mode 100644 index d06012ad6d..0000000000 --- a/Release/tests/functional/http/utilities/vs14/HttpTestUtilities140.vcxproj +++ /dev/null @@ -1,218 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {6837625b-c0db-4fd0-aee2-19699031b76e} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\include;%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - -Zm200 %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - -Zm140 %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - -Zm200 %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - -Zm200 %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - -Zm140 %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - -Zm200 %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - Winhttp.lib;Httpapi.lib;%(AdditionalDependencies) - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/http/utilities/vs14/HttpTestUtilities140.vcxproj.filters b/Release/tests/functional/http/utilities/vs14/HttpTestUtilities140.vcxproj.filters deleted file mode 100644 index 1e583ce8ed..0000000000 --- a/Release/tests/functional/http/utilities/vs14/HttpTestUtilities140.vcxproj.filters +++ /dev/null @@ -1,51 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - {d0052d1d-10e0-42da-9df6-72be473a8ebe} - - - {a4317631-da2e-4508-982f-e689f8d4a039} - - - \ No newline at end of file diff --git a/Release/tests/functional/json/CMakeLists.txt b/Release/tests/functional/json/CMakeLists.txt index 379a6bd4bf..1d44a99ce6 100644 --- a/Release/tests/functional/json/CMakeLists.txt +++ b/Release/tests/functional/json/CMakeLists.txt @@ -5,7 +5,6 @@ set(SOURCES to_as_and_operators_tests.cpp iterator_tests.cpp json_numbers_tests.cpp - stdafx.cpp ) if(NOT WINDOWS_STORE AND NOT WINDOWS_PHONE) list(APPEND SOURCES fuzz_tests.cpp) @@ -16,3 +15,16 @@ if(UNIX AND NOT APPLE) cpprest_find_boost() target_link_libraries(json_test PRIVATE cpprestsdk_boost_internal) endif() + +if(MSVC) + get_target_property(_srcs json_test SOURCES) + + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") + set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/json-tests-stdafx.pch") + set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/json-tests-stdafx.pch") + endif() + + set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h /Fpjson-tests-stdafx.pch") + target_sources(json_test PRIVATE stdafx.cpp) + target_compile_options(json_test PRIVATE /Yustdafx.h /Fpjson-tests-stdafx.pch) +endif() diff --git a/Release/tests/functional/json/vs14.android/JSON140_test.android.vcxproj b/Release/tests/functional/json/vs14.android/JSON140_test.android.vcxproj deleted file mode 100644 index 16dd72d5bc..0000000000 --- a/Release/tests/functional/json/vs14.android/JSON140_test.android.vcxproj +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - Debug - ARM - - - Debug - x86 - - - Release - ARM - - - Release - x86 - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - {7c4e6e33-42e2-4472-9319-dde7564f3dae} - - - - {169555EF-8A80-405E-A815-CFE70028CA45} - Android - Android - 2.0 - JSON140_test.android - - - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - - - - 378b82c3 - - - - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Enabled - c++11 - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - d - - - JSON140_test.android - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - diff --git a/Release/tests/functional/json/vs14.android/JSON140_test.android.vcxproj.filters b/Release/tests/functional/json/vs14.android/JSON140_test.android.vcxproj.filters deleted file mode 100644 index 9d4e307758..0000000000 --- a/Release/tests/functional/json/vs14.android/JSON140_test.android.vcxproj.filters +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - {ea88708b-1006-422c-b275-3f1394e595c8} - - - {9142d997-6ead-4b83-a03f-9e03e4da038d} - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/tests/functional/json/vs14.uwp/JSON140_test.uwp.vcxproj b/Release/tests/functional/json/vs14.uwp/JSON140_test.uwp.vcxproj deleted file mode 100644 index b2b05a4d50..0000000000 --- a/Release/tests/functional/json/vs14.uwp/JSON140_test.uwp.vcxproj +++ /dev/null @@ -1,128 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {D398DF71-8642-4BC4-940F-9AE2B0AE1CE4} - Windows Store - en-US - 14.0 - true - Unicode - v140 - DynamicLibrary - 10.0.10240.0 - 10.0.10240.0 - - - - true - - - false - true - - - - - - - Use - WIN32;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - false - false - stdafx.h - -Zm250 %(AdditionalOptions) - - - Console - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - {DA089EAD-00A2-43CF-9954-DF01E8ED5E94} - - - {04214181-57D7-45F5-8499-1A5530CE6CBF} - - - {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/json/vs14.uwp/JSON140_test.uwp.vcxproj.filters b/Release/tests/functional/json/vs14.uwp/JSON140_test.uwp.vcxproj.filters deleted file mode 100644 index ae62883eba..0000000000 --- a/Release/tests/functional/json/vs14.uwp/JSON140_test.uwp.vcxproj.filters +++ /dev/null @@ -1,42 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - {db714d7a-c017-4d4f-99ab-f1f195ba360c} - - - {3ea4dfd5-d8b3-4370-adda-ea04dcaf401b} - - - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/functional/json/vs14.xp/JSON140_test.xp.vcxproj b/Release/tests/functional/json/vs14.xp/JSON140_test.xp.vcxproj deleted file mode 100644 index 6b4e8ee881..0000000000 --- a/Release/tests/functional/json/vs14.xp/JSON140_test.xp.vcxproj +++ /dev/null @@ -1,151 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {ABA69F91-45D4-41D8-991A-10A6319E42C3} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath14) - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - - - Console - true - $(OutDir)%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - - - Console - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {75885703-7f3d-4086-8e60-c60b9b126f7e} - - - {5AD81270-B089-4E1B-8741-6486F39DE273} - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/json/vs14/JSON140_test.vcxproj b/Release/tests/functional/json/vs14/JSON140_test.vcxproj deleted file mode 100644 index 58928de7d0..0000000000 --- a/Release/tests/functional/json/vs14/JSON140_test.vcxproj +++ /dev/null @@ -1,211 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {6f026328-4d10-4ef1-bd6c-8fd3cbe0f530} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - FastCall - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - FastCall - - - Console - true - $(OutDir)%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - FastCall - - - Console - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - FastCall - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - FastCall - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;COMMONTESTS_EXPORTS;%(PreprocessorDefinitions) - FastCall - - - Console - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/json/vs14/JSON140_test.vcxproj.filters b/Release/tests/functional/json/vs14/JSON140_test.vcxproj.filters deleted file mode 100644 index 9908627f9a..0000000000 --- a/Release/tests/functional/json/vs14/JSON140_test.vcxproj.filters +++ /dev/null @@ -1,47 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/functional/misc/version/vs14/version140_test.vcxproj b/Release/tests/functional/misc/version/vs14/version140_test.vcxproj deleted file mode 100644 index f62231600c..0000000000 --- a/Release/tests/functional/misc/version/vs14/version140_test.vcxproj +++ /dev/null @@ -1,100 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {1263db26-9035-43c4-adab-a2c71ae92cce} - Win32Proj - version - SAK - SAK - SAK - SAK - version - - - - DynamicLibrary - Unicode - v140 - - - - - - - - - - - - - - NotUsing - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;HEADER_TEST_EXPORTS;%(PreprocessorDefinitions);_AFXDLL - $(CommonTestIncludeDir);$(CasablancaIncludeDir);%(AdditionalIncludeDirectories) - MultiThreadedDebugDLL - - - Windows - true - - - - - - NotUsing - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HEADER_TEST_EXPORTS;%(PreprocessorDefinitions);_AFXDLL - $(CommonTestIncludeDir);$(CasablancaIncludeDir);%(AdditionalIncludeDirectories) - MultiThreadedDLL - - - Windows - true - true - true - - - - - - _VER_MAJOR=$(CppRestSDKVersionMajor);_VER_MINOR=$(CppRestSDKVersionMinor);_VER_REVISION=$(CppRestSDKVersionRevision);%(PreprocessorDefinitions) - - - - - - - - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/pplx/pplx_test/CMakeLists.txt b/Release/tests/functional/pplx/pplx_test/CMakeLists.txt index 01c56f7522..0e2672b73e 100644 --- a/Release/tests/functional/pplx/pplx_test/CMakeLists.txt +++ b/Release/tests/functional/pplx/pplx_test/CMakeLists.txt @@ -2,7 +2,19 @@ set(SOURCES pplx_op_test.cpp pplx_task_options.cpp pplxtask_tests.cpp - stdafx.cpp ) add_casablanca_test(pplx_test SOURCES) + +if(MSVC) + get_target_property(_srcs pplx_test SOURCES) + + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") + set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/pplx-tests-stdafx.pch") + set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pplx-tests-stdafx.pch") + endif() + + set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h /Fppplx-tests-stdafx.pch") + target_sources(pplx_test PRIVATE stdafx.cpp) + target_compile_options(pplx_test PRIVATE /Yustdafx.h /Fppplx-tests-stdafx.pch) +endif() diff --git a/Release/tests/functional/pplx/pplx_test/vs14.android/pplx140_test.android.vcxproj b/Release/tests/functional/pplx/pplx_test/vs14.android/pplx140_test.android.vcxproj deleted file mode 100644 index 7fd3c7b631..0000000000 --- a/Release/tests/functional/pplx/pplx_test/vs14.android/pplx140_test.android.vcxproj +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - Debug - ARM - - - Debug - x86 - - - Release - ARM - - - Release - x86 - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - {7c4e6e33-42e2-4472-9319-dde7564f3dae} - - - - {DF670B4E-692C-424E-BCFD-F63D34FE5CD3} - Android - Android - 2.0 - pplx140_test.android - - - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - - - - 378b82c3 - - - - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Enabled - c++11 - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - d - - - pplx140_test.android - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - diff --git a/Release/tests/functional/pplx/pplx_test/vs14.uwp/pplx140_test.uwp.vcxproj b/Release/tests/functional/pplx/pplx_test/vs14.uwp/pplx140_test.uwp.vcxproj deleted file mode 100644 index b42ef70c16..0000000000 --- a/Release/tests/functional/pplx/pplx_test/vs14.uwp/pplx140_test.uwp.vcxproj +++ /dev/null @@ -1,130 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {23A43AC2-1E04-4589-B0A9-0295962755DC} - Win32Proj - HttpTests - SAK - SAK - SAK - SAK - en-US - 14.0 - true - DynamicLibrary - v140 - 10.0.10240.0 - 10.0.10240.0 - Unicode - - - - true - - - false - true - - - - - - - Use - WIN32;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - /bigobj %(AdditionalOptions) - true - false - stdafx.h - - - Windows - true - CommonUtilities140.uwp.lib;%(AdditionalDependencies) - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {DA089EAD-00A2-43CF-9954-DF01E8ED5E94} - - - {04214181-57D7-45F5-8499-1A5530CE6CBF} - - - {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/pplx/pplx_test/vs14.xp/pplx140_test.xp.vcxproj b/Release/tests/functional/pplx/pplx_test/vs14.xp/pplx140_test.xp.vcxproj deleted file mode 100644 index bedd4efee8..0000000000 --- a/Release/tests/functional/pplx/pplx_test/vs14.xp/pplx140_test.xp.vcxproj +++ /dev/null @@ -1,158 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {EB4A3750-CA93-4968-89D7-3ED467DB2C59} - Win32Proj - HttpTests - SAK - SAK - SAK - SAK - $(VCTargetsPath14) - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Level4 - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Level4 - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Level4 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Level4 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - Create - Create - Create - Create - - - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {5ad81270-b089-4e1b-8741-6486f39de273} - - - {75885703-7F3D-4086-8E60-C60B9B126F7E} - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/pplx/pplx_test/vs14/pplx140_test.vcxproj b/Release/tests/functional/pplx/pplx_test/vs14/pplx140_test.vcxproj deleted file mode 100644 index 95c586743b..0000000000 --- a/Release/tests/functional/pplx/pplx_test/vs14/pplx140_test.vcxproj +++ /dev/null @@ -1,212 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {06F8344D-4EBA-4B9F-A209-5FCEFA9D62EB} - Win32Proj - HttpTests - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Level3 - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Level3 - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Level3 - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/streams/CMakeLists.txt b/Release/tests/functional/streams/CMakeLists.txt index 4b11173b18..29d09bbac8 100644 --- a/Release/tests/functional/streams/CMakeLists.txt +++ b/Release/tests/functional/streams/CMakeLists.txt @@ -4,7 +4,6 @@ set(SOURCES memstream_tests.cpp ostream_tests.cpp stdstream_tests.cpp - stdafx.cpp ) if(WINDOWS_STORE OR WINDOWS_PHONE) list(APPEND SOURCES winrt_interop_tests.cpp) @@ -24,3 +23,16 @@ if(NOT WIN32 OR CPPREST_WEBSOCKETS_IMPL STREQUAL "wspp") target_include_directories(streams_test PRIVATE $) endif() endif() + +if(MSVC) + get_target_property(_srcs streams_test SOURCES) + + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") + set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/streams-tests-stdafx.pch") + set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/streams-tests-stdafx.pch") + endif() + + set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h /Fpstreams-tests-stdafx.pch") + target_sources(streams_test PRIVATE stdafx.cpp) + target_compile_options(streams_test PRIVATE /Yustdafx.h /Fpstreams-tests-stdafx.pch) +endif() diff --git a/Release/tests/functional/streams/vs14.android/streams140_test.android.vcxproj b/Release/tests/functional/streams/vs14.android/streams140_test.android.vcxproj deleted file mode 100644 index 81ff3ad878..0000000000 --- a/Release/tests/functional/streams/vs14.android/streams140_test.android.vcxproj +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - Debug - ARM - - - Debug - x86 - - - Release - ARM - - - Release - x86 - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - {7c4e6e33-42e2-4472-9319-dde7564f3dae} - - - - {B9DA540F-95F7-485E-ADF4-C94A17BFA1EB} - Android - Android - 2.0 - streams140_test.android - - - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - - - - 378b82c3 - - - - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Enabled - c++11 - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - d - - - streams140_test.android - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - diff --git a/Release/tests/functional/streams/vs14.android/streams140_test.android.vcxproj.filters b/Release/tests/functional/streams/vs14.android/streams140_test.android.vcxproj.filters deleted file mode 100644 index 2288fd4da5..0000000000 --- a/Release/tests/functional/streams/vs14.android/streams140_test.android.vcxproj.filters +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - {086f8ce7-3abe-46b1-a418-069737cb878b} - - - {5a4e8b16-a7c4-439b-afb3-c4a50dbfb681} - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - \ No newline at end of file diff --git a/Release/tests/functional/streams/vs14.uwp/streams140_test.uwp.vcxproj b/Release/tests/functional/streams/vs14.uwp/streams140_test.uwp.vcxproj deleted file mode 100644 index 11b8c9404d..0000000000 --- a/Release/tests/functional/streams/vs14.uwp/streams140_test.uwp.vcxproj +++ /dev/null @@ -1,137 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {B4C6E439-20F9-406C-9586-792FB5B073C2} - Win32Proj - SAK - SAK - SAK - SAK - en-US - 14.0 - true - v140 - DynamicLibrary - e13f21ed - 10.0.10240.0 - 10.0.10240.0 - - - - true - - - false - true - - - - - - - Use - WIN32;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - /bigobj %(AdditionalOptions) - true - false - stdafx.h - -Zm160 %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - {DA089EAD-00A2-43CF-9954-DF01E8ED5E94} - - - {04214181-57D7-45F5-8499-1A5530CE6CBF} - - - {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/streams/vs14.uwp/streams140_test.uwp.vcxproj.filters b/Release/tests/functional/streams/vs14.uwp/streams140_test.uwp.vcxproj.filters deleted file mode 100644 index 86b36e3575..0000000000 --- a/Release/tests/functional/streams/vs14.uwp/streams140_test.uwp.vcxproj.filters +++ /dev/null @@ -1,45 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - {274676f3-573c-4a10-adbb-0421159c8a2a} - - - {dd303bf1-0c87-4079-a035-c16d23cf129d} - - - - - Header Files - - - Header Files - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/streams/vs14.xp/streams140_test.xp.vcxproj b/Release/tests/functional/streams/vs14.xp/streams140_test.xp.vcxproj deleted file mode 100644 index cdd4ff6820..0000000000 --- a/Release/tests/functional/streams/vs14.xp/streams140_test.xp.vcxproj +++ /dev/null @@ -1,163 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {F279F1ED-8AFF-478D-9A20-DDCAD8CBA336} - Win32Proj - HttpTests - SAK - SAK - SAK - SAK - $(VCTargetsPath14) - 2276c549 - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {75885703-7f3d-4086-8e60-c60b9b126f7e} - - - {5ad81270-b089-4e1b-8741-6486f39de273} - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/streams/vs14/streams140_test.vcxproj b/Release/tests/functional/streams/vs14/streams140_test.vcxproj deleted file mode 100644 index 07520fe5ac..0000000000 --- a/Release/tests/functional/streams/vs14/streams140_test.vcxproj +++ /dev/null @@ -1,219 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {181ccb80-9ae8-4ed7-8b7d-4c0cbc80eedd} - Win32Proj - HttpTests - SAK - SAK - SAK - SAK - $(VCTargetsPath12) - 84fd5b75 - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - StdCall - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - ARM;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - StdCall - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - StdCall - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - StdCall - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - ARM;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - StdCall - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;HTTPTESTS_EXPORTS;%(PreprocessorDefinitions) - /bigobj %(AdditionalOptions) - StdCall - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/streams/vs14/streams140_test.vcxproj.filters b/Release/tests/functional/streams/vs14/streams140_test.vcxproj.filters deleted file mode 100644 index fec2efca0f..0000000000 --- a/Release/tests/functional/streams/vs14/streams140_test.vcxproj.filters +++ /dev/null @@ -1,43 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - - {1de3a9ce-57af-48bd-8125-3af4f406be26} - - - {3c2936bc-8d1e-4a33-96c9-5cfb3d83b30d} - - - - - Header Files - - - Header Files - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/uri/CMakeLists.txt b/Release/tests/functional/uri/CMakeLists.txt index 54d80ac254..e3f7de1da2 100644 --- a/Release/tests/functional/uri/CMakeLists.txt +++ b/Release/tests/functional/uri/CMakeLists.txt @@ -9,7 +9,19 @@ set(SOURCES splitting_tests.cpp uri_builder_tests.cpp resolve_uri_tests.cpp - stdafx.cpp ) add_casablanca_test(uri_test SOURCES) + +if(MSVC) + get_target_property(_srcs uri_test SOURCES) + + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") + set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/uri-tests-stdafx.pch") + set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/uri-tests-stdafx.pch") + endif() + + set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h /Fpuri-tests-stdafx.pch") + target_sources(uri_test PRIVATE stdafx.cpp) + target_compile_options(uri_test PRIVATE /Yustdafx.h /Fpuri-tests-stdafx.pch) +endif() diff --git a/Release/tests/functional/uri/vs14.android/Uri140_test.android.vcxproj b/Release/tests/functional/uri/vs14.android/Uri140_test.android.vcxproj deleted file mode 100644 index bf66be6210..0000000000 --- a/Release/tests/functional/uri/vs14.android/Uri140_test.android.vcxproj +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - Debug - ARM - - - Debug - x86 - - - Release - ARM - - - Release - x86 - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - {7c4e6e33-42e2-4472-9319-dde7564f3dae} - - - - {63569C1A-A168-442A-B160-76D0256803AF} - Android - Android - 2.0 - Uri140_test.android - - - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - - - - 378b82c3 - - - - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Enabled - c++11 - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - d - - - Uri140_test.android - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - diff --git a/Release/tests/functional/uri/vs14.android/Uri140_test.android.vcxproj.filters b/Release/tests/functional/uri/vs14.android/Uri140_test.android.vcxproj.filters deleted file mode 100644 index ca869127a3..0000000000 --- a/Release/tests/functional/uri/vs14.android/Uri140_test.android.vcxproj.filters +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - {2a91a18a-e13e-4f80-8066-55d069396647} - - - {9ee2024f-1bd0-452f-bdf2-14f9dd9998d1} - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/tests/functional/uri/vs14.uwp/URI140_test.uwp.vcxproj.filters b/Release/tests/functional/uri/vs14.uwp/URI140_test.uwp.vcxproj.filters deleted file mode 100644 index fd4f136ea8..0000000000 --- a/Release/tests/functional/uri/vs14.uwp/URI140_test.uwp.vcxproj.filters +++ /dev/null @@ -1,57 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - {e30fa8ae-3cb4-4a63-870b-a7e85088a9ad} - - - {e7f8af98-2e23-4c57-93e1-2936a3f0ac84} - - - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/functional/uri/vs14.uwp/Uri140_test.uwp.vcxproj b/Release/tests/functional/uri/vs14.uwp/Uri140_test.uwp.vcxproj deleted file mode 100644 index 3225698298..0000000000 --- a/Release/tests/functional/uri/vs14.uwp/Uri140_test.uwp.vcxproj +++ /dev/null @@ -1,136 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {9169C20C-B98A-46C6-A138-A107C458E8DD} - SAK - SAK - SAK - SAK - Win32Proj - en-US - 14.0 - true - DynamicLibrary - Unicode - v140 - 10.0.10240.0 - 10.0.10240.0 - - - - true - - - false - true - - - - - - - Use - WIN32;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - true - false - stdafx.h - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {DA089EAD-00A2-43CF-9954-DF01E8ED5E94} - - - {04214181-57D7-45F5-8499-1A5530CE6CBF} - - - {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} - - - - - - - - - - - - - diff --git a/Release/tests/functional/uri/vs14.xp/Uri140_test.xp.vcxproj b/Release/tests/functional/uri/vs14.xp/Uri140_test.xp.vcxproj deleted file mode 100644 index 988d387b15..0000000000 --- a/Release/tests/functional/uri/vs14.xp/Uri140_test.xp.vcxproj +++ /dev/null @@ -1,155 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {66B6D1E2-A91C-4DA3-8568-B7457FA7ED6D} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath14) - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {75885703-7f3d-4086-8e60-c60b9b126f7e} - - - {5ad81270-b089-4e1b-8741-6486f39de273} - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/uri/vs14/Uri140_test.vcxproj b/Release/tests/functional/uri/vs14/Uri140_test.vcxproj deleted file mode 100644 index c7758a2a41..0000000000 --- a/Release/tests/functional/uri/vs14/Uri140_test.vcxproj +++ /dev/null @@ -1,212 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {3d9c3f25-1736-4d39-a31f-6b2de34e20cf} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - StdCall - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - StdCall - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - StdCall - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - StdCall - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - StdCall - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - StdCall - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/uri/vs14/Uri140_test.vcxproj.filters b/Release/tests/functional/uri/vs14/Uri140_test.vcxproj.filters deleted file mode 100644 index a05e44e9f0..0000000000 --- a/Release/tests/functional/uri/vs14/Uri140_test.vcxproj.filters +++ /dev/null @@ -1,53 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/functional/utils/CMakeLists.txt b/Release/tests/functional/utils/CMakeLists.txt index ff175283f8..201af77039 100644 --- a/Release/tests/functional/utils/CMakeLists.txt +++ b/Release/tests/functional/utils/CMakeLists.txt @@ -5,7 +5,6 @@ set(SOURCES macro_test.cpp nonce_generator_tests.cpp win32_encryption_tests.cpp - stdafx.cpp ) add_casablanca_test(utils_test SOURCES) @@ -13,3 +12,16 @@ add_casablanca_test(utils_test SOURCES) if(CMAKE_COMPILER_IS_GNUCXX) target_compile_options(utils_test PRIVATE "-Wno-deprecated-declarations") endif() + +if(MSVC) + get_target_property(_srcs utils_test SOURCES) + + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*") + set_property(SOURCE stdafx.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/utils-tests-stdafx.pch") + set_property(SOURCE ${_srcs} APPEND PROPERTY OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/utils-tests-stdafx.pch") + endif() + + set_source_files_properties(stdafx.cpp PROPERTIES COMPILE_FLAGS "/Ycstdafx.h /Fputils-tests-stdafx.pch") + target_sources(utils_test PRIVATE stdafx.cpp) + target_compile_options(utils_test PRIVATE /Yustdafx.h /Fputils-tests-stdafx.pch) +endif() diff --git a/Release/tests/functional/utils/vs14.android/Utils140_test.android.vcxproj b/Release/tests/functional/utils/vs14.android/Utils140_test.android.vcxproj deleted file mode 100644 index 3bffb9f385..0000000000 --- a/Release/tests/functional/utils/vs14.android/Utils140_test.android.vcxproj +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - Debug - ARM - - - Debug - x86 - - - Release - ARM - - - Release - x86 - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - {7c4e6e33-42e2-4472-9319-dde7564f3dae} - - - - {423FCE6D-7400-4C09-9038-4438FBB089D4} - Android - Android - 2.0 - Utils140_test.android - - - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - - - - 378b82c3 - - - - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Enabled - c++11 - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - d - - - Utils140_test.android - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - diff --git a/Release/tests/functional/utils/vs14.android/Utils140_test.android.vcxproj.filters b/Release/tests/functional/utils/vs14.android/Utils140_test.android.vcxproj.filters deleted file mode 100644 index 72c7afdac7..0000000000 --- a/Release/tests/functional/utils/vs14.android/Utils140_test.android.vcxproj.filters +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - {22ca4c16-d08f-4f8d-9a72-1177da20c0e9} - - - {c59c025e-d09f-4eff-8553-3ec14490cdc0} - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/Release/tests/functional/utils/vs14.uwp/Utils140_test.uwp.vcxproj b/Release/tests/functional/utils/vs14.uwp/Utils140_test.uwp.vcxproj deleted file mode 100644 index e02821bda3..0000000000 --- a/Release/tests/functional/utils/vs14.uwp/Utils140_test.uwp.vcxproj +++ /dev/null @@ -1,131 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {4fddc511-5cfd-48a0-b373-43b13a43fb45} - SAK - SAK - SAK - SAK - Win32Proj - en-US - 14.0 - true - Unicode - v140 - DynamicLibrary - 10.0.10240.0 - 10.0.10240.0 - - - - true - - - false - true - - - - - - - Use - WIN32;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir) - true - false - stdafx.h - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {DA089EAD-00A2-43CF-9954-DF01E8ED5E94} - - - {04214181-57D7-45F5-8499-1A5530CE6CBF} - - - {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} - - - - - - - - - - - - - diff --git a/Release/tests/functional/utils/vs14.uwp/Utils140_test.uwp.vcxproj.filters b/Release/tests/functional/utils/vs14.uwp/Utils140_test.uwp.vcxproj.filters deleted file mode 100644 index a2199f62fb..0000000000 --- a/Release/tests/functional/utils/vs14.uwp/Utils140_test.uwp.vcxproj.filters +++ /dev/null @@ -1,36 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - {e30fa8ae-3cb4-4a63-870b-a7e85088a9ad} - - - {e7f8af98-2e23-4c57-93e1-2936a3f0ac84} - - - Source Files - - - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/functional/utils/vs14.xp/Utils140_test.xp.vcxproj b/Release/tests/functional/utils/vs14.xp/Utils140_test.xp.vcxproj deleted file mode 100644 index 45ee435b2b..0000000000 --- a/Release/tests/functional/utils/vs14.xp/Utils140_test.xp.vcxproj +++ /dev/null @@ -1,151 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {E9E26CDB-4CE3-4B0E-AAF8-D32F57E48856} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath14) - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {75885703-7f3d-4086-8e60-c60b9b126f7e} - - - {5ad81270-b089-4e1b-8741-6486f39de273} - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/utils/vs14/Utils140_test.vcxproj b/Release/tests/functional/utils/vs14/Utils140_test.vcxproj deleted file mode 100644 index 37cd0326f0..0000000000 --- a/Release/tests/functional/utils/vs14/Utils140_test.vcxproj +++ /dev/null @@ -1,208 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {50386698-0180-4ebc-8827-f2c36561f6b4} - SAK - SAK - SAK - SAK - Win32Proj - $(VCTargetsPath12) - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - $(CasablancaIncludeDir);$(CommonTestIncludeDir);%(AdditionalIncludeDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - StdCall - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - StdCall - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - StdCall - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - StdCall - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - StdCall - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - StdCall - - - Windows - true - true - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {3EB86C0D-432C-4FFC-BAD4-8DF4EFC7D0FF} - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/utils/vs14/Utils140_test.vcxproj.filters b/Release/tests/functional/utils/vs14/Utils140_test.vcxproj.filters deleted file mode 100644 index dfa7b86991..0000000000 --- a/Release/tests/functional/utils/vs14/Utils140_test.vcxproj.filters +++ /dev/null @@ -1,38 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/Release/tests/functional/websockets/client/vs14.android/websocketsclient140_test.android.vcxproj b/Release/tests/functional/websockets/client/vs14.android/websocketsclient140_test.android.vcxproj deleted file mode 100644 index 230810860b..0000000000 --- a/Release/tests/functional/websockets/client/vs14.android/websocketsclient140_test.android.vcxproj +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - Debug - ARM - - - Debug - x86 - - - Release - ARM - - - Release - x86 - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - {0149e1c2-fbf3-48b6-9996-d6753f689dfb} - - - - {3E8466B1-7CBC-489D-8E6B-5E45BAB4D627} - Android - Android - 2.0 - websocketsclient140_test.android - - - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - - - - 378b82c3 - - - - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(TestRoot)\functional\websockets\utilities;%(AdditionalIncludeDirectories) - Enabled - c++11 - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);$(TestRoot)\functional\websockets\utilities;%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(TestRoot)\functional\websockets\utilities;%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(TestRoot)\functional\websockets\utilities;%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - d - - - websocketsclient140_test.android - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - diff --git a/Release/tests/functional/websockets/client/vs14.uwp/websocketsclient140_test.uwp.vcxproj b/Release/tests/functional/websockets/client/vs14.uwp/websocketsclient140_test.uwp.vcxproj deleted file mode 100644 index 17ba6a3ffb..0000000000 --- a/Release/tests/functional/websockets/client/vs14.uwp/websocketsclient140_test.uwp.vcxproj +++ /dev/null @@ -1,127 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {CE900295-F777-446C-8954-894891F0A9D4} - SAK - SAK - SAK - SAK - en-US - 14.0 - true - DynamicLibrary - Unicode - v140 - 10.0.10240.0 - 10.0.10240.0 - - - - true - - - false - true - - - - - - - Use - WIN32;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\..\utilities; - true - false - stdafx.h - - - Windows - true - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - -Zm200 %(AdditionalOptions) - - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - -Zm200 %(AdditionalOptions) - - - true - true - - - - - - {DA089EAD-00A2-43CF-9954-DF01E8ED5E94} - - - {04214181-57D7-45F5-8499-1A5530CE6CBF} - - - {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} - - - {D452C5CF-681B-4B64-B3A9-A916E842988F} - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/websockets/client/vs14.xp/websocketsclient140_test.xp.vcxproj b/Release/tests/functional/websockets/client/vs14.xp/websocketsclient140_test.xp.vcxproj deleted file mode 100644 index 9791f3d90c..0000000000 --- a/Release/tests/functional/websockets/client/vs14.xp/websocketsclient140_test.xp.vcxproj +++ /dev/null @@ -1,123 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - WebsocketTests - SAK - SAK - SAK - SAK - websocketsclient140_test.xp - {BBE711C0-568C-48E5-A9EB-2F3741D0687B} - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - Use - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\..\utilities;%(AdditionalIncludeDirectories) - - - Windows - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Disabled - CPPREST_TARGET_XP;WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - - - MaxSpeed - true - true - CPPREST_TARGET_XP;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - true - true - - - - - {75885703-7f3d-4086-8e60-c60b9b126f7e} - - - {3eb86c0d-432c-4ffc-bad4-8df4efc7d0ff} - - - {5AD81270-B089-4E1B-8741-6486F39DE273} - - - {3803246A-F31E-44EC-BCA9-87DF68C5EB8D} - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - diff --git a/Release/tests/functional/websockets/client/vs14/websocketsclient140_test.vcxproj b/Release/tests/functional/websockets/client/vs14/websocketsclient140_test.vcxproj deleted file mode 100644 index 9d23e7da8a..0000000000 --- a/Release/tests/functional/websockets/client/vs14/websocketsclient140_test.vcxproj +++ /dev/null @@ -1,125 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {9A23F9D2-4876-423B-9393-A604764601B0} - WebsocketTests - SAK - SAK - SAK - SAK - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - Use - $(CasablancaIncludeDir);$(CommonTestIncludeDir);..\..\utilities;%(AdditionalIncludeDirectories) - -Zm200 %(AdditionalOptions) - - - Windows - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - - - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - - - true - true - - - - - {1014c621-bc2d-4813-b8c1-6d83ad6f9249} - - - {3eb86c0d-432c-4ffc-bad4-8df4efc7d0ff} - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {14f7b7a0-a057-4e15-8ec4-12baf00b0f64} - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - diff --git a/Release/tests/functional/websockets/utilities/vs14.android/packages.config b/Release/tests/functional/websockets/utilities/vs14.android/packages.config deleted file mode 100644 index 4bd0fd80ad..0000000000 --- a/Release/tests/functional/websockets/utilities/vs14.android/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/Release/tests/functional/websockets/utilities/vs14.android/websockets_test_utilities140.android.vcxproj b/Release/tests/functional/websockets/utilities/vs14.android/websockets_test_utilities140.android.vcxproj deleted file mode 100644 index 3962040a52..0000000000 --- a/Release/tests/functional/websockets/utilities/vs14.android/websockets_test_utilities140.android.vcxproj +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - Debug - ARM - - - Debug - x86 - - - Release - ARM - - - Release - x86 - - - - - Create - Create - Create - Create - - - - - - - - - - - - - {7c4e6e33-42e2-4472-9319-dde7564f3dae} - - - - {0149E1C2-FBF3-48B6-9996-D6753F689DFB} - Android - Android - 2.0 - websockets_test_utilities140.android - - - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - true - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - StaticLibrary - false - Clang_3_8 - gnustl_static - - - - - - 378b82c3 - - - - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - Enabled - c++11 - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);$(StlIncludeDirectories);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-arm\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - - EnableAllWarnings - $(NDKRoot)\platforms\$(AndroidAPILevel)\arch-x86\usr\include;$(StlIncludeDirectories);$(CasablancaIncludeDir);$(TestRoot)\functional\http\utilities\include;$(CommonTestIncludeDir);$(CasablancaSrcDir)\pch;$(WebsocketppIncludeDir);%(AdditionalIncludeDirectories) - c++11 - Enabled - true - true - -funwind-tables -Wno-unused-local-typedef %(AdditionalOptions) - - - - d - - - websockets_test_utilities140.android - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - diff --git a/Release/tests/functional/websockets/utilities/vs14.uwp/packages.config b/Release/tests/functional/websockets/utilities/vs14.uwp/packages.config deleted file mode 100644 index 7438d474dd..0000000000 --- a/Release/tests/functional/websockets/utilities/vs14.uwp/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/websockets/utilities/vs14.uwp/websockets_test_utilities140.uwp.vcxproj b/Release/tests/functional/websockets/utilities/vs14.uwp/websockets_test_utilities140.uwp.vcxproj deleted file mode 100644 index 71c92e1697..0000000000 --- a/Release/tests/functional/websockets/utilities/vs14.uwp/websockets_test_utilities140.uwp.vcxproj +++ /dev/null @@ -1,147 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {D452C5CF-681B-4B64-B3A9-A916E842988F} - SAK - SAK - SAK - SAK - Win32Proj - en-US - 14.0 - Unicode - v140 - DynamicLibrary - Windows Store - 10.0.10240.0 - 10.0.10240.0 - - - - true - - - false - true - - - - - - Use - WIN32;_USRDLL;WEBSOCKETTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(WebsocketppIncludeDir);..\include - $(WindowsSdkDir)\UnionMetadata;$(VSInstallDir)\vc\vcpackages;$(AdditionalUsingDirectories) - -Zm200 %(AdditionalOptions) - true - false - stdafx.h - - - Windows - true - true - CommonUtilities140.uwp.lib;Ws2_32.lib;Mswsock.lib;%(AdditionalDependencies) - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - $(VCINSTALLDIR)\lib\store;$(OutDir);%(AdditionalLibraryDirectories); - ucrtd.lib;vcruntimed.lib;vccorlibd.lib;msvcrtd.lib;msvcprtd.lib;concrtd.lib;RuntimeObject.lib;libboost_system-vc140-mt-gd-1_58.lib;%(AdditionalDependencies) - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions) - - - $(VCINSTALLDIR)\lib\store\amd64;$(OutDir);%(AdditionalLibraryDirectories); - ucrtd.lib;vcruntimed.lib;vccorlibd.lib;msvcrtd.lib;msvcprtd.lib;concrtd.lib;RuntimeObject.lib;libboost_system-vc140-mt-gd-1_58.lib;%(AdditionalDependencies) - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - $(VCINSTALLDIR)\lib\store;$(OutDir);%(AdditionalLibraryDirectories); - ucrt.lib;vcruntime.lib;vccorlib.lib;msvcrt.lib;msvcprt.lib;concrt.lib;RuntimeObject.lib;libboost_system-vc140-mt-1_58.lib;%(AdditionalDependencies) - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions) - - - true - true - $(VCINSTALLDIR)\lib\store\amd64;$(OutDir);%(AdditionalLibraryDirectories); - ucrt.lib;vcruntime.lib;vccorlib.lib;msvcrt.lib;msvcprt.lib;concrt.lib;RuntimeObject.lib;libboost_system-vc140-mt-1_58.lib;%(AdditionalDependencies) - - - - - {DA089EAD-00A2-43CF-9954-DF01E8ED5E94} - - - {04214181-57D7-45F5-8499-1A5530CE6CBF} - - - {36d79e79-7e9e-4b3a-88a3-9f9b295c80b9} - - - - - - Create - Create - Create - Create - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/websockets/utilities/vs14.xp/websockets_test_utilities140.xp.vcxproj b/Release/tests/functional/websockets/utilities/vs14.xp/websockets_test_utilities140.xp.vcxproj deleted file mode 100644 index c1410e701a..0000000000 --- a/Release/tests/functional/websockets/utilities/vs14.xp/websockets_test_utilities140.xp.vcxproj +++ /dev/null @@ -1,132 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - SAK - SAK - SAK - SAK - Win32Proj - en-US - 11.0 - tests::common::websockets_test_utilities - websockets_test_utilities140.xp - {3803246A-F31E-44EC-BCA9-87DF68C5EB8D} - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - Use - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(WebsocketppIncludeDir);$(TestRoot)\Common\UnitTestpp\src\;%(AdditionalIncludeDirectories) - - - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - 4503;%(DisableSpecificWarnings) - - - Windows - $(OutDir);%(AdditionalLibraryDirectories) - - - - - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;WEBSOCKETTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - - - - - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;WEBSOCKETTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - - - true - true - - - - - - Create - Create - Create - Create - - - - - - - - - {3eb86c0d-432c-4ffc-bad4-8df4efc7d0ff} - - - {75885703-7f3d-4086-8e60-c60b9b126f7e} - - - {5AD81270-B089-4E1B-8741-6486F39DE273} - - - - - - - - - - - - - diff --git a/Release/tests/functional/websockets/utilities/vs14/packages.config b/Release/tests/functional/websockets/utilities/vs14/packages.config deleted file mode 100644 index 7438d474dd..0000000000 --- a/Release/tests/functional/websockets/utilities/vs14/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/Release/tests/functional/websockets/utilities/vs14/websockets_test_utilities140.vcxproj b/Release/tests/functional/websockets/utilities/vs14/websockets_test_utilities140.vcxproj deleted file mode 100644 index 23eb5b26c3..0000000000 --- a/Release/tests/functional/websockets/utilities/vs14/websockets_test_utilities140.vcxproj +++ /dev/null @@ -1,151 +0,0 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - {14F7B7A0-A057-4E15-8EC4-12BAF00B0F64} - SAK - SAK - SAK - SAK - Win32Proj - en-US - 11.0 - tests::common::websockets_test_utilities - websockets_test_utilities140 - - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - DynamicLibrary - false - true - Unicode - v140 - - - - - - - Use - $(CasablancaIncludeDir);$(CommonTestIncludeDir);$(WebsocketppIncludeDir);$(TestRoot)\Common\UnitTestpp\src\;%(AdditionalIncludeDirectories) - 4503;%(DisableSpecificWarnings) - -Zm200 /bigobj %(AdditionalOptions) - - - Windows - $(OutDir);%(AdditionalLibraryDirectories) - - - - - - Disabled - _DEBUG;_WINDOWS;_USRDLL;WEBSOCKETTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - - - - - MaxSpeed - true - true - NDEBUG;_WINDOWS;_USRDLL;WEBSOCKETTESTUTILITY_EXPORTS;%(PreprocessorDefinitions) - - - true - true - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - {0c9d50d9-94fb-4732-a4ad-58e068315bb2} - - - {3eb86c0d-432c-4ffc-bad4-8df4efc7d0ff} - - - {90D85FF4-F0AE-4816-923F-0EF2758F30AB} - - - - - - - - - - - - - diff --git a/build.root b/build.root deleted file mode 100644 index d423a1a70c..0000000000 --- a/build.root +++ /dev/null @@ -1 +0,0 @@ -Marker file indicating root of build system. diff --git a/cpprestsdk140.sln b/cpprestsdk140.sln deleted file mode 100644 index 4a9087e936..0000000000 --- a/cpprestsdk140.sln +++ /dev/null @@ -1,292 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprestsdk140", "Release\src\build\vs14\casablanca140.vcxproj", "{1014C621-BC2D-4813-B8C1-6D83AD6F9249}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "android", "Release\src\build\android.vcxitems", "{65951C40-A332-4B54-89C2-7CDAF30D5F66}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "Release\src\build\common.vcxitems", "{594DCB5F-07E3-4084-A2CE-268611FA629F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "other", "Release\src\build\other.vcxitems", "{3D5908F7-7673-4229-BC46-2007A7AF9CAE}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win32", "Release\src\build\win32.vcxitems", "{F40F4804-50F9-4257-8D74-B9CBB19AC4C3}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winrt", "Release\src\build\winrt.vcxitems", "{0A9BA181-7876-4B3D-A5E0-EE673FA51C05}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{64F2F240-04BE-43B2-97BE-DA47FDFE8393}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{B572F8D5-9728-409C-AB5E-063C7D3CA781}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BingRequest", "BingRequest", "{00EF03C1-74A9-4832-B26B-E6478C2A96AC}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BlackJack", "BlackJack", "{B6F7411C-FE75-4CD2-A384-083A526FE6DF}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CasaLens", "CasaLens", "{76FA5645-FF99-44C0-87DB-B96AFAC2F800}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SearchFile", "SearchFile", "{22309B46-EE6F-45D0-A993-2F45D98DEF22}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BingRequest140", "Release\samples\BingRequest\BingRequest140\BingRequest140.vcxproj", "{2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{8E54A174-9108-45BF-8080-92A916C43A54}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Server", "Server", "{DADA0A65-A970-4114-8F9C-EA3327F90712}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlackJack_Client140", "Release\samples\BlackJack\BlackJack_Client\BlackJack_Client140\BlackJack_Client140.vcxproj", "{830B6E2F-9224-41D1-B9C7-A51FC78B00C7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlackJack_Server140", "Release\samples\BlackJack\BlackJack_Server\BlackJack_Server140\BlackJack_Server140.vcxproj", "{84350CD1-D406-4A4F-9571-261CA46D77C5}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CasaLens140", "Release\samples\CasaLens\CasaLens140\CasaLens140.vcxproj", "{FFBFD6C1-B525-4D35-AB64-A2FE9460B147}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SearchFile140", "Release\samples\SearchFile\SearchFile140\SearchFile140.vcxproj", "{F03BEE03-BEFB-4B17-A774-D9C8246530D4}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprestsdk140.android", "Release\src\build\vs14.android\casablanca140.android.vcxproj", "{AFB49019-965B-4C10-BAFF-C86C16D58010}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprestsdk140.uwp", "Release\src\build\vs14.uwp\cpprestsdk140.uwp.vcxproj", "{36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprestsdk140.uwp.staticlib", "Release\src\build\vs14.uwp\cpprestsdk140.uwp.staticlib.vcxproj", "{47A5CFDC-C244-45A6-9830-38CB303CB495}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprestsdk140.static", "Release\src\build\vs14.static\casablanca140.static.vcxproj", "{79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprestsdk140.xp", "Release\src\build\vs14.xp\casablanca140.xp.vcxproj", "{39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BingRequest140.xp", "Release\samples\BingRequest\BingRequest140.xp\BingRequest140.xp.vcxproj", "{7009BCBE-D67C-4B54-BEFC-A44E62656CF1}" -EndProject -Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - Release\src\build\winrt.vcxitems*{0a9ba181-7876-4b3d-a5e0-ee673fa51c05}*SharedItemsImports = 9 - Release\src\build\android.vcxitems*{65951c40-a332-4b54-89c2-7cdaf30d5f66}*SharedItemsImports = 9 - Release\src\build\winrt.vcxitems*{47a5cfdc-c244-45a6-9830-38cb303cb495}*SharedItemsImports = 4 - Release\src\build\common.vcxitems*{47a5cfdc-c244-45a6-9830-38cb303cb495}*SharedItemsImports = 4 - Release\src\build\win32.vcxitems*{1014c621-bc2d-4813-b8c1-6d83ad6f9249}*SharedItemsImports = 4 - Release\src\build\common.vcxitems*{1014c621-bc2d-4813-b8c1-6d83ad6f9249}*SharedItemsImports = 4 - Release\src\build\winrt.vcxitems*{36d79e79-7e9e-4b3a-88a3-9f9b295c80b9}*SharedItemsImports = 4 - Release\src\build\common.vcxitems*{36d79e79-7e9e-4b3a-88a3-9f9b295c80b9}*SharedItemsImports = 4 - Release\src\build\android.vcxitems*{afb49019-965b-4c10-baff-c86c16d58010}*SharedItemsImports = 4 - Release\src\build\common.vcxitems*{afb49019-965b-4c10-baff-c86c16d58010}*SharedItemsImports = 4 - Release\src\build\win32.vcxitems*{79c9bbec-d7c9-4ba3-b2b3-5c3a14a9f24a}*SharedItemsImports = 4 - Release\src\build\common.vcxitems*{79c9bbec-d7c9-4ba3-b2b3-5c3a14a9f24a}*SharedItemsImports = 4 - Release\src\build\win32.vcxitems*{39f7e851-7ef8-4dfb-9907-b480cb8d2ac9}*SharedItemsImports = 4 - Release\src\build\common.vcxitems*{39f7e851-7ef8-4dfb-9907-b480cb8d2ac9}*SharedItemsImports = 4 - Release\src\build\win32.vcxitems*{f40f4804-50f9-4257-8d74-b9cbb19ac4c3}*SharedItemsImports = 9 - Release\src\build\other.vcxitems*{3d5908f7-7673-4229-bc46-2007a7af9cae}*SharedItemsImports = 9 - Release\src\build\common.vcxitems*{594dcb5f-07e3-4084-a2ce-268611fa629f}*SharedItemsImports = 9 - EndGlobalSection - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|ARM = Debug|ARM - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|ARM = Release|ARM - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|ARM.ActiveCfg = Debug|ARM - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|Win32.ActiveCfg = Debug|Win32 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|Win32.Build.0 = Debug|Win32 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|x64.ActiveCfg = Debug|x64 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|x64.Build.0 = Debug|x64 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|x86.ActiveCfg = Debug|Win32 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|x86.Build.0 = Debug|Win32 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|ARM.ActiveCfg = Release|ARM - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|Win32.ActiveCfg = Release|Win32 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|Win32.Build.0 = Release|Win32 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|x64.ActiveCfg = Release|x64 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|x64.Build.0 = Release|x64 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|x86.ActiveCfg = Release|Win32 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|x86.Build.0 = Release|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|ARM.ActiveCfg = Debug|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|Win32.ActiveCfg = Debug|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|Win32.Build.0 = Debug|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|x64.ActiveCfg = Debug|x64 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|x64.Build.0 = Debug|x64 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|x86.ActiveCfg = Debug|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|x86.Build.0 = Debug|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|ARM.ActiveCfg = Release|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|Win32.ActiveCfg = Release|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|Win32.Build.0 = Release|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x64.ActiveCfg = Release|x64 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x64.Build.0 = Release|x64 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x86.ActiveCfg = Release|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x86.Build.0 = Release|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|ARM.ActiveCfg = Debug|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|Win32.ActiveCfg = Debug|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|Win32.Build.0 = Debug|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|x64.ActiveCfg = Debug|x64 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|x64.Build.0 = Debug|x64 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|x86.ActiveCfg = Debug|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|x86.Build.0 = Debug|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|ARM.ActiveCfg = Release|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|Win32.ActiveCfg = Release|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|Win32.Build.0 = Release|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|x64.ActiveCfg = Release|x64 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|x64.Build.0 = Release|x64 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|x86.ActiveCfg = Release|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|x86.Build.0 = Release|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|ARM.ActiveCfg = Debug|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|Win32.ActiveCfg = Debug|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|Win32.Build.0 = Debug|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|x64.ActiveCfg = Debug|x64 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|x64.Build.0 = Debug|x64 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|x86.ActiveCfg = Debug|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|x86.Build.0 = Debug|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|ARM.ActiveCfg = Release|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|Win32.ActiveCfg = Release|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|Win32.Build.0 = Release|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|x64.ActiveCfg = Release|x64 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|x64.Build.0 = Release|x64 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|x86.ActiveCfg = Release|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|x86.Build.0 = Release|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|ARM.ActiveCfg = Debug|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|Win32.ActiveCfg = Debug|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|Win32.Build.0 = Debug|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|x64.ActiveCfg = Debug|x64 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|x64.Build.0 = Debug|x64 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|x86.ActiveCfg = Debug|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|x86.Build.0 = Debug|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|ARM.ActiveCfg = Release|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|Win32.ActiveCfg = Release|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|Win32.Build.0 = Release|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|x64.ActiveCfg = Release|x64 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|x64.Build.0 = Release|x64 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|x86.ActiveCfg = Release|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|x86.Build.0 = Release|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|ARM.ActiveCfg = Debug|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|Win32.ActiveCfg = Debug|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|Win32.Build.0 = Debug|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|x64.ActiveCfg = Debug|x64 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|x64.Build.0 = Debug|x64 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|x86.ActiveCfg = Debug|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|x86.Build.0 = Debug|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|ARM.ActiveCfg = Release|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|Win32.ActiveCfg = Release|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|Win32.Build.0 = Release|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|x64.ActiveCfg = Release|x64 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|x64.Build.0 = Release|x64 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|x86.ActiveCfg = Release|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|x86.Build.0 = Release|Win32 - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|ARM.ActiveCfg = Debug|ARM - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|ARM.Build.0 = Debug|ARM - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|Win32.ActiveCfg = Debug|x86 - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|Win32.Build.0 = Debug|x86 - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|x64.ActiveCfg = Debug|x86 - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|x86.ActiveCfg = Debug|x86 - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|x86.Build.0 = Debug|x86 - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|ARM.ActiveCfg = Release|ARM - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|ARM.Build.0 = Release|ARM - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|Win32.ActiveCfg = Release|x86 - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|Win32.Build.0 = Release|x86 - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|x64.ActiveCfg = Release|x86 - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|x86.ActiveCfg = Release|x86 - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|x86.Build.0 = Release|x86 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|ARM.ActiveCfg = Debug|ARM - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|ARM.Build.0 = Debug|ARM - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|Win32.ActiveCfg = Debug|Win32 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|Win32.Build.0 = Debug|Win32 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|x64.ActiveCfg = Debug|x64 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|x64.Build.0 = Debug|x64 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|x86.ActiveCfg = Debug|Win32 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|x86.Build.0 = Debug|Win32 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|ARM.ActiveCfg = Release|ARM - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|ARM.Build.0 = Release|ARM - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|Win32.ActiveCfg = Release|Win32 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|Win32.Build.0 = Release|Win32 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|x64.ActiveCfg = Release|x64 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|x64.Build.0 = Release|x64 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|x86.ActiveCfg = Release|Win32 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|x86.Build.0 = Release|Win32 - {47A5CFDC-C244-45A6-9830-38CB303CB495}.Debug|ARM.ActiveCfg = Debug|ARM - {47A5CFDC-C244-45A6-9830-38CB303CB495}.Debug|ARM.Build.0 = Debug|ARM - {47A5CFDC-C244-45A6-9830-38CB303CB495}.Debug|Win32.ActiveCfg = Debug|Win32 - {47A5CFDC-C244-45A6-9830-38CB303CB495}.Debug|Win32.Build.0 = Debug|Win32 - {47A5CFDC-C244-45A6-9830-38CB303CB495}.Debug|x64.ActiveCfg = Debug|x64 - {47A5CFDC-C244-45A6-9830-38CB303CB495}.Debug|x64.Build.0 = Debug|x64 - {47A5CFDC-C244-45A6-9830-38CB303CB495}.Debug|x86.ActiveCfg = Debug|Win32 - {47A5CFDC-C244-45A6-9830-38CB303CB495}.Debug|x86.Build.0 = Debug|Win32 - {47A5CFDC-C244-45A6-9830-38CB303CB495}.Release|ARM.ActiveCfg = Release|ARM - {47A5CFDC-C244-45A6-9830-38CB303CB495}.Release|ARM.Build.0 = Release|ARM - {47A5CFDC-C244-45A6-9830-38CB303CB495}.Release|Win32.ActiveCfg = Release|Win32 - {47A5CFDC-C244-45A6-9830-38CB303CB495}.Release|Win32.Build.0 = Release|Win32 - {47A5CFDC-C244-45A6-9830-38CB303CB495}.Release|x64.ActiveCfg = Release|x64 - {47A5CFDC-C244-45A6-9830-38CB303CB495}.Release|x64.Build.0 = Release|x64 - {47A5CFDC-C244-45A6-9830-38CB303CB495}.Release|x86.ActiveCfg = Release|Win32 - {47A5CFDC-C244-45A6-9830-38CB303CB495}.Release|x86.Build.0 = Release|Win32 - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}.Debug|ARM.ActiveCfg = Debug|ARM - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}.Debug|ARM.Build.0 = Debug|ARM - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}.Debug|Win32.ActiveCfg = Debug|Win32 - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}.Debug|Win32.Build.0 = Debug|Win32 - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}.Debug|x64.ActiveCfg = Debug|x64 - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}.Debug|x64.Build.0 = Debug|x64 - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}.Debug|x86.ActiveCfg = Debug|Win32 - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}.Debug|x86.Build.0 = Debug|Win32 - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}.Release|ARM.ActiveCfg = Release|ARM - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}.Release|ARM.Build.0 = Release|ARM - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}.Release|Win32.ActiveCfg = Release|Win32 - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}.Release|Win32.Build.0 = Release|Win32 - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}.Release|x64.ActiveCfg = Release|x64 - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}.Release|x64.Build.0 = Release|x64 - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}.Release|x86.ActiveCfg = Release|Win32 - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A}.Release|x86.Build.0 = Release|Win32 - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}.Debug|ARM.ActiveCfg = Debug|ARM - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}.Debug|ARM.Build.0 = Debug|ARM - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}.Debug|Win32.ActiveCfg = Debug|Win32 - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}.Debug|Win32.Build.0 = Debug|Win32 - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}.Debug|x64.ActiveCfg = Debug|x64 - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}.Debug|x64.Build.0 = Debug|x64 - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}.Debug|x86.ActiveCfg = Debug|Win32 - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}.Debug|x86.Build.0 = Debug|Win32 - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}.Release|ARM.ActiveCfg = Release|ARM - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}.Release|ARM.Build.0 = Release|ARM - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}.Release|Win32.ActiveCfg = Release|Win32 - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}.Release|Win32.Build.0 = Release|Win32 - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}.Release|x64.ActiveCfg = Release|x64 - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}.Release|x64.Build.0 = Release|x64 - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}.Release|x86.ActiveCfg = Release|Win32 - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9}.Release|x86.Build.0 = Release|Win32 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Debug|ARM.ActiveCfg = Debug|Win32 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Debug|Win32.ActiveCfg = Debug|Win32 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Debug|Win32.Build.0 = Debug|Win32 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Debug|x64.ActiveCfg = Debug|x64 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Debug|x64.Build.0 = Debug|x64 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Debug|x86.ActiveCfg = Debug|Win32 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Debug|x86.Build.0 = Debug|Win32 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Release|ARM.ActiveCfg = Release|Win32 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Release|Win32.ActiveCfg = Release|Win32 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Release|Win32.Build.0 = Release|Win32 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Release|x64.ActiveCfg = Release|x64 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Release|x64.Build.0 = Release|x64 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Release|x86.ActiveCfg = Release|Win32 - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} = {64F2F240-04BE-43B2-97BE-DA47FDFE8393} - {65951C40-A332-4B54-89C2-7CDAF30D5F66} = {64F2F240-04BE-43B2-97BE-DA47FDFE8393} - {594DCB5F-07E3-4084-A2CE-268611FA629F} = {64F2F240-04BE-43B2-97BE-DA47FDFE8393} - {3D5908F7-7673-4229-BC46-2007A7AF9CAE} = {64F2F240-04BE-43B2-97BE-DA47FDFE8393} - {F40F4804-50F9-4257-8D74-B9CBB19AC4C3} = {64F2F240-04BE-43B2-97BE-DA47FDFE8393} - {0A9BA181-7876-4B3D-A5E0-EE673FA51C05} = {64F2F240-04BE-43B2-97BE-DA47FDFE8393} - {00EF03C1-74A9-4832-B26B-E6478C2A96AC} = {B572F8D5-9728-409C-AB5E-063C7D3CA781} - {B6F7411C-FE75-4CD2-A384-083A526FE6DF} = {B572F8D5-9728-409C-AB5E-063C7D3CA781} - {76FA5645-FF99-44C0-87DB-B96AFAC2F800} = {B572F8D5-9728-409C-AB5E-063C7D3CA781} - {22309B46-EE6F-45D0-A993-2F45D98DEF22} = {B572F8D5-9728-409C-AB5E-063C7D3CA781} - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D} = {00EF03C1-74A9-4832-B26B-E6478C2A96AC} - {8E54A174-9108-45BF-8080-92A916C43A54} = {B6F7411C-FE75-4CD2-A384-083A526FE6DF} - {DADA0A65-A970-4114-8F9C-EA3327F90712} = {B6F7411C-FE75-4CD2-A384-083A526FE6DF} - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7} = {8E54A174-9108-45BF-8080-92A916C43A54} - {84350CD1-D406-4A4F-9571-261CA46D77C5} = {DADA0A65-A970-4114-8F9C-EA3327F90712} - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147} = {76FA5645-FF99-44C0-87DB-B96AFAC2F800} - {F03BEE03-BEFB-4B17-A774-D9C8246530D4} = {22309B46-EE6F-45D0-A993-2F45D98DEF22} - {AFB49019-965B-4C10-BAFF-C86C16D58010} = {64F2F240-04BE-43B2-97BE-DA47FDFE8393} - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9} = {64F2F240-04BE-43B2-97BE-DA47FDFE8393} - {47A5CFDC-C244-45A6-9830-38CB303CB495} = {64F2F240-04BE-43B2-97BE-DA47FDFE8393} - {79C9BBEC-D7C9-4BA3-B2B3-5C3A14A9F24A} = {64F2F240-04BE-43B2-97BE-DA47FDFE8393} - {39F7E851-7EF8-4DFB-9907-B480CB8D2AC9} = {64F2F240-04BE-43B2-97BE-DA47FDFE8393} - {7009BCBE-D67C-4B54-BEFC-A44E62656CF1} = {00EF03C1-74A9-4832-B26B-E6478C2A96AC} - EndGlobalSection -EndGlobal diff --git a/cpprestsdk141.sln b/cpprestsdk141.sln deleted file mode 100644 index f4ed2d2d51..0000000000 --- a/cpprestsdk141.sln +++ /dev/null @@ -1,258 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27018.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "android", "Release\src\build\android.vcxitems", "{65951C40-A332-4B54-89C2-7CDAF30D5F66}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "Release\src\build\common.vcxitems", "{594DCB5F-07E3-4084-A2CE-268611FA629F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "other", "Release\src\build\other.vcxitems", "{3D5908F7-7673-4229-BC46-2007A7AF9CAE}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win32", "Release\src\build\win32.vcxitems", "{F40F4804-50F9-4257-8D74-B9CBB19AC4C3}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winrt", "Release\src\build\winrt.vcxitems", "{0A9BA181-7876-4B3D-A5E0-EE673FA51C05}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{92944FCF-7E50-41FD-8A99-DD6869F9AEA5}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprest141", "Release\src\build\vs141\cpprest141.vcxproj", "{1014C621-BC2D-4813-B8C1-6D83AD6F9249}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprest141.uwp", "Release\src\build\vs141.uwp\cpprest141.uwp.vcxproj", "{36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{EF775754-D70A-4611-A00C-F49F224FD236}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SearchFile141", "Release\samples\SearchFile\SearchFile141\SearchFile141.vcxproj", "{F03BEE03-BEFB-4B17-A774-D9C8246530D4}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OAuth2Live141", "Release\samples\OAuth2Live\OAuth2Live141.vcxproj", "{2887A786-B818-4B3D-94EF-21EFD6AFDC22}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Oauth2Client141", "Release\samples\Oauth2Client\Oauth2Client141\Oauth2Client141.vcxproj", "{35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Oauth1Client141", "Release\samples\Oauth1Client\Oauth1Client141\Oauth1Client141.vcxproj", "{850CCB95-CFA8-4E41-9D1D-387C0C186740}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FacebookDemo141", "Release\samples\FacebookDemo\FacebookDemo141.vcxproj", "{43DE4DF3-ACAA-429E-B260-CC6D4FE82658}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CasaLens141", "Release\samples\CasaLens\CasaLens141\CasaLens141.vcxproj", "{FFBFD6C1-B525-4D35-AB64-A2FE9460B147}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlackJack_UIClient141", "Release\samples\BlackJack\BlackJack_UIClient\BlackJack_UIClient141.vcxproj", "{B8D3F85B-DA71-4ACA-87BA-10FED681DC79}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlackJack_Server141", "Release\samples\BlackJack\BlackJack_Server\BlackJack_Server141\BlackJack_Server141.vcxproj", "{84350CD1-D406-4A4F-9571-261CA46D77C5}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlackJack_Client141", "Release\samples\BlackJack\BlackJack_Client\BlackJack_Client141\BlackJack_Client141.vcxproj", "{830B6E2F-9224-41D1-B9C7-A51FC78B00C7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BingRequest141", "Release\samples\BingRequest\BingRequest141\BingRequest141.vcxproj", "{2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpprest141.android", "Release\src\build\vs141.android\cpprest141.android.vcxproj", "{AFB49019-965B-4C10-BAFF-C86C16D58010}" -EndProject -Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - Release\src\build\winrt.vcxitems*{0a9ba181-7876-4b3d-a5e0-ee673fa51c05}*SharedItemsImports = 9 - Release\src\build\common.vcxitems*{1014c621-bc2d-4813-b8c1-6d83ad6f9249}*SharedItemsImports = 4 - Release\src\build\win32.vcxitems*{1014c621-bc2d-4813-b8c1-6d83ad6f9249}*SharedItemsImports = 4 - Release\src\build\common.vcxitems*{36d79e79-7e9e-4b3a-88a3-9f9b295c80b9}*SharedItemsImports = 4 - Release\src\build\winrt.vcxitems*{36d79e79-7e9e-4b3a-88a3-9f9b295c80b9}*SharedItemsImports = 4 - Release\src\build\other.vcxitems*{3d5908f7-7673-4229-bc46-2007a7af9cae}*SharedItemsImports = 9 - Release\src\build\common.vcxitems*{594dcb5f-07e3-4084-a2ce-268611fa629f}*SharedItemsImports = 9 - Release\src\build\android.vcxitems*{65951c40-a332-4b54-89c2-7cdaf30d5f66}*SharedItemsImports = 9 - Release\src\build\android.vcxitems*{afb49019-965b-4c10-baff-c86c16d58010}*SharedItemsImports = 4 - Release\src\build\common.vcxitems*{afb49019-965b-4c10-baff-c86c16d58010}*SharedItemsImports = 4 - Release\src\build\win32.vcxitems*{f40f4804-50f9-4257-8d74-b9cbb19ac4c3}*SharedItemsImports = 9 - EndGlobalSection - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|ARM = Debug|ARM - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|ARM = Release|ARM - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|ARM.ActiveCfg = Debug|ARM - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|ARM.Build.0 = Debug|ARM - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|x64.ActiveCfg = Debug|x64 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|x64.Build.0 = Debug|x64 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|x86.ActiveCfg = Debug|Win32 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Debug|x86.Build.0 = Debug|Win32 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|ARM.ActiveCfg = Release|ARM - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|ARM.Build.0 = Release|ARM - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|x64.ActiveCfg = Release|x64 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|x64.Build.0 = Release|x64 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|x86.ActiveCfg = Release|Win32 - {1014C621-BC2D-4813-B8C1-6D83AD6F9249}.Release|x86.Build.0 = Release|Win32 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|ARM.ActiveCfg = Debug|ARM - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|ARM.Build.0 = Debug|ARM - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|x64.ActiveCfg = Debug|x64 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|x64.Build.0 = Debug|x64 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|x86.ActiveCfg = Debug|Win32 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Debug|x86.Build.0 = Debug|Win32 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|ARM.ActiveCfg = Release|ARM - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|ARM.Build.0 = Release|ARM - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|x64.ActiveCfg = Release|x64 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|x64.Build.0 = Release|x64 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|x86.ActiveCfg = Release|Win32 - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9}.Release|x86.Build.0 = Release|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|ARM.ActiveCfg = Debug|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|x64.ActiveCfg = Debug|x64 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|x64.Build.0 = Debug|x64 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|x86.ActiveCfg = Debug|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Debug|x86.Build.0 = Debug|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|ARM.ActiveCfg = Release|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|x64.ActiveCfg = Release|x64 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|x64.Build.0 = Release|x64 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|x86.ActiveCfg = Release|Win32 - {F03BEE03-BEFB-4B17-A774-D9C8246530D4}.Release|x86.Build.0 = Release|Win32 - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|ARM.ActiveCfg = Debug|ARM - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|ARM.Build.0 = Debug|ARM - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|ARM.Deploy.0 = Debug|ARM - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|x64.ActiveCfg = Debug|x64 - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|x64.Build.0 = Debug|x64 - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|x64.Deploy.0 = Debug|x64 - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|x86.ActiveCfg = Debug|Win32 - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|x86.Build.0 = Debug|Win32 - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Debug|x86.Deploy.0 = Debug|Win32 - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|ARM.ActiveCfg = Release|ARM - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|ARM.Build.0 = Release|ARM - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|ARM.Deploy.0 = Release|ARM - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|x64.ActiveCfg = Release|x64 - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|x64.Build.0 = Release|x64 - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|x64.Deploy.0 = Release|x64 - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|x86.ActiveCfg = Release|Win32 - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|x86.Build.0 = Release|Win32 - {2887A786-B818-4B3D-94EF-21EFD6AFDC22}.Release|x86.Deploy.0 = Release|Win32 - {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Debug|ARM.ActiveCfg = Debug|ARM - {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Debug|ARM.Build.0 = Debug|ARM - {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Debug|x64.ActiveCfg = Debug|x64 - {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Debug|x64.Build.0 = Debug|x64 - {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Debug|x86.ActiveCfg = Debug|Win32 - {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Debug|x86.Build.0 = Debug|Win32 - {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Release|ARM.ActiveCfg = Release|ARM - {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Release|ARM.Build.0 = Release|ARM - {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Release|x64.ActiveCfg = Release|x64 - {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Release|x64.Build.0 = Release|x64 - {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Release|x86.ActiveCfg = Release|Win32 - {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654}.Release|x86.Build.0 = Release|Win32 - {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Debug|ARM.ActiveCfg = Debug|ARM - {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Debug|ARM.Build.0 = Debug|ARM - {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Debug|x64.ActiveCfg = Debug|x64 - {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Debug|x64.Build.0 = Debug|x64 - {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Debug|x86.ActiveCfg = Debug|Win32 - {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Debug|x86.Build.0 = Debug|Win32 - {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Release|ARM.ActiveCfg = Release|ARM - {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Release|ARM.Build.0 = Release|ARM - {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Release|x64.ActiveCfg = Release|x64 - {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Release|x64.Build.0 = Release|x64 - {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Release|x86.ActiveCfg = Release|Win32 - {850CCB95-CFA8-4E41-9D1D-387C0C186740}.Release|x86.Build.0 = Release|Win32 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|ARM.ActiveCfg = Debug|ARM - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|ARM.Build.0 = Debug|ARM - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|ARM.Deploy.0 = Debug|ARM - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|x64.ActiveCfg = Debug|x64 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|x64.Build.0 = Debug|x64 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|x64.Deploy.0 = Debug|x64 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|x86.ActiveCfg = Debug|Win32 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|x86.Build.0 = Debug|Win32 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Debug|x86.Deploy.0 = Debug|Win32 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|ARM.ActiveCfg = Release|ARM - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|ARM.Build.0 = Release|ARM - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|ARM.Deploy.0 = Release|ARM - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|x64.ActiveCfg = Release|x64 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|x64.Build.0 = Release|x64 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|x64.Deploy.0 = Release|x64 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|x86.ActiveCfg = Release|Win32 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|x86.Build.0 = Release|Win32 - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658}.Release|x86.Deploy.0 = Release|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|ARM.ActiveCfg = Debug|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|x64.ActiveCfg = Debug|x64 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|x64.Build.0 = Debug|x64 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|x86.ActiveCfg = Debug|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Debug|x86.Build.0 = Debug|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|ARM.ActiveCfg = Release|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|x64.ActiveCfg = Release|x64 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|x64.Build.0 = Release|x64 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|x86.ActiveCfg = Release|Win32 - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147}.Release|x86.Build.0 = Release|Win32 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|ARM.ActiveCfg = Debug|ARM - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|ARM.Build.0 = Debug|ARM - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|ARM.Deploy.0 = Debug|ARM - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|x64.ActiveCfg = Debug|x64 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|x64.Build.0 = Debug|x64 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|x64.Deploy.0 = Debug|x64 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|x86.ActiveCfg = Debug|Win32 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|x86.Build.0 = Debug|Win32 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Debug|x86.Deploy.0 = Debug|Win32 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|ARM.ActiveCfg = Release|ARM - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|ARM.Build.0 = Release|ARM - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|ARM.Deploy.0 = Release|ARM - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|x64.ActiveCfg = Release|x64 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|x64.Build.0 = Release|x64 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|x64.Deploy.0 = Release|x64 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|x86.ActiveCfg = Release|Win32 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|x86.Build.0 = Release|Win32 - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79}.Release|x86.Deploy.0 = Release|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|ARM.ActiveCfg = Debug|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|x64.ActiveCfg = Debug|x64 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|x64.Build.0 = Debug|x64 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|x86.ActiveCfg = Debug|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Debug|x86.Build.0 = Debug|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|ARM.ActiveCfg = Release|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|x64.ActiveCfg = Release|x64 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|x64.Build.0 = Release|x64 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|x86.ActiveCfg = Release|Win32 - {84350CD1-D406-4A4F-9571-261CA46D77C5}.Release|x86.Build.0 = Release|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|ARM.ActiveCfg = Debug|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|x64.ActiveCfg = Debug|x64 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|x64.Build.0 = Debug|x64 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|x86.ActiveCfg = Debug|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Debug|x86.Build.0 = Debug|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|ARM.ActiveCfg = Release|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|x64.ActiveCfg = Release|x64 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|x64.Build.0 = Release|x64 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|x86.ActiveCfg = Release|Win32 - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7}.Release|x86.Build.0 = Release|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|ARM.ActiveCfg = Debug|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|x64.ActiveCfg = Debug|x64 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|x64.Build.0 = Debug|x64 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|x86.ActiveCfg = Debug|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Debug|x86.Build.0 = Debug|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|ARM.ActiveCfg = Release|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x64.ActiveCfg = Release|x64 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x64.Build.0 = Release|x64 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x86.ActiveCfg = Release|Win32 - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D}.Release|x86.Build.0 = Release|Win32 - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|ARM.ActiveCfg = Debug|ARM - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|ARM.Build.0 = Debug|ARM - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|x64.ActiveCfg = Debug|x86 - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|x86.ActiveCfg = Debug|x86 - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Debug|x86.Build.0 = Debug|x86 - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|ARM.ActiveCfg = Release|ARM - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|ARM.Build.0 = Release|ARM - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|x64.ActiveCfg = Release|x86 - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|x86.ActiveCfg = Release|x86 - {AFB49019-965B-4C10-BAFF-C86C16D58010}.Release|x86.Build.0 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {65951C40-A332-4B54-89C2-7CDAF30D5F66} = {92944FCF-7E50-41FD-8A99-DD6869F9AEA5} - {594DCB5F-07E3-4084-A2CE-268611FA629F} = {92944FCF-7E50-41FD-8A99-DD6869F9AEA5} - {3D5908F7-7673-4229-BC46-2007A7AF9CAE} = {92944FCF-7E50-41FD-8A99-DD6869F9AEA5} - {F40F4804-50F9-4257-8D74-B9CBB19AC4C3} = {92944FCF-7E50-41FD-8A99-DD6869F9AEA5} - {0A9BA181-7876-4B3D-A5E0-EE673FA51C05} = {92944FCF-7E50-41FD-8A99-DD6869F9AEA5} - {1014C621-BC2D-4813-B8C1-6D83AD6F9249} = {92944FCF-7E50-41FD-8A99-DD6869F9AEA5} - {36D79E79-7E9E-4B3A-88A3-9F9B295C80B9} = {92944FCF-7E50-41FD-8A99-DD6869F9AEA5} - {F03BEE03-BEFB-4B17-A774-D9C8246530D4} = {EF775754-D70A-4611-A00C-F49F224FD236} - {2887A786-B818-4B3D-94EF-21EFD6AFDC22} = {EF775754-D70A-4611-A00C-F49F224FD236} - {35DFAAD1-4B25-4ED9-BB18-84F0EFCE1654} = {EF775754-D70A-4611-A00C-F49F224FD236} - {850CCB95-CFA8-4E41-9D1D-387C0C186740} = {EF775754-D70A-4611-A00C-F49F224FD236} - {43DE4DF3-ACAA-429E-B260-CC6D4FE82658} = {EF775754-D70A-4611-A00C-F49F224FD236} - {FFBFD6C1-B525-4D35-AB64-A2FE9460B147} = {EF775754-D70A-4611-A00C-F49F224FD236} - {B8D3F85B-DA71-4ACA-87BA-10FED681DC79} = {EF775754-D70A-4611-A00C-F49F224FD236} - {84350CD1-D406-4A4F-9571-261CA46D77C5} = {EF775754-D70A-4611-A00C-F49F224FD236} - {830B6E2F-9224-41D1-B9C7-A51FC78B00C7} = {EF775754-D70A-4611-A00C-F49F224FD236} - {2EB9CCAA-541D-4DC1-BE2C-B1AE9712194D} = {EF775754-D70A-4611-A00C-F49F224FD236} - {AFB49019-965B-4C10-BAFF-C86C16D58010} = {92944FCF-7E50-41FD-8A99-DD6869F9AEA5} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {5782CB9E-B335-4D07-A195-717BF4093536} - EndGlobalSection -EndGlobal From b209ac17d994fa082d182b05b35a2e9fb7c0d801 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Mon, 15 Oct 2018 13:48:26 -0700 Subject: [PATCH 279/438] Add vcpkg based dependency resolution for *nix platforms. (#913) --- .gitmodules | 2 +- azure-pipelines.yml | 102 +++++++++++++++++++++++++++++++++----------- vcpkg | 2 +- 3 files changed, 79 insertions(+), 27 deletions(-) diff --git a/.gitmodules b/.gitmodules index 3c19d8d07f..326611e519 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "vcpkg"] path = vcpkg - url = https://github.com/Microsoft/vcpkg + url = https://github.com/BillyONeal/vcpkg diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 76766a59b4..a5d63c55df 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -166,31 +166,46 @@ jobs: cd build.release/Release/Binaries ./test_runner *test.so displayName: 'Run tests, release' - - # vcpkg on Linux missing for now due to OpenSSL root certificates - # - job: Ubuntu_1604_Vcpkg_Debug - # pool: - # vmImage: 'Ubuntu 16.04' - # steps: - # - script: | - # ./vcpkg/bootstrap-vcpkg.sh - # ./vcpkg/vcpkg install zlib openssl boost-system boost-date-time boost-regex websocketpp boost-thread boost-filesystem boost-random boost-chrono - # displayName: Apt install dependencies - # - script: mkdir build.debug - # displayName: Make build.debug - # - task: CMake@1 - # inputs: - # workingDirectory: 'build.debug' - # cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' - # - script: | - # cd build.debug - # ninja - # displayName: 'Run ninja' - # - script: | - # cd build.debug/Release/Binaries - # ./test_runner *test.so - # displayName: 'Run Tests' - - job: MacOS + - job: Ubuntu_1604_Vcpkg + pool: + vmImage: 'Ubuntu 16.04' + steps: + - script: | + sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y + sudo apt-get -y update + sudo apt-get install g++-7 ninja-build -y + ./vcpkg/bootstrap-vcpkg.sh + ./vcpkg/vcpkg install zlib openssl boost-system boost-date-time boost-regex websocketpp boost-thread boost-filesystem boost-random boost-chrono boost-interprocess brotli + displayName: Vcpkg install dependencies + - script: | + mkdir build.debug + mkdir build.release + displayName: Make Build Directories + - task: CMake@1 + inputs: + workingDirectory: 'build.debug' + cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + - task: CMake@1 + inputs: + workingDirectory: 'build.release' + cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + - script: | + cd build.debug + ninja + displayName: 'Run ninja debug' + - script: | + cd build.debug/Release/Binaries + ./test_runner *test.so + displayName: 'Run Tests debug' + - script: | + cd build.release + ninja + displayName: 'Run ninja, release' + - script: | + cd build.release/Release/Binaries + ./test_runner *test.so + displayName: 'Run tests, release' + - job: MacOS_Homebrew pool: vmImage: 'macOS-10.13' steps: @@ -233,3 +248,40 @@ jobs: cd build.release.static ninja displayName: 'Run ninja, release static' + - job: MacOS_Vcpkg + pool: + vmImage: 'macOS-10.13' + steps: + - script: | + brew install gcc ninja + ./vcpkg/bootstrap-vcpkg.sh + ./vcpkg/vcpkg install zlib openssl boost-system boost-date-time boost-regex websocketpp boost-thread boost-filesystem boost-random boost-chrono boost-interprocess brotli + displayName: Vcpkg install dependencies + - script: | + mkdir build.debug + mkdir build.release + displayName: Make Build Directories + - task: CMake@1 + inputs: + workingDirectory: 'build.debug' + cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + - task: CMake@1 + inputs: + workingDirectory: 'build.release' + cmakeArgs: '-G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..' + - script: | + cd build.debug + ninja + displayName: 'Run ninja debug' + - script: | + cd build.debug/Release/Binaries + ./test_runner *test.dylib + displayName: 'Run Tests debug' + - script: | + cd build.release + ninja + displayName: 'Run ninja, release' + - script: | + cd build.release/Release/Binaries + ./test_runner *test.dylib + displayName: 'Run tests, release' diff --git a/vcpkg b/vcpkg index 29858b3cb2..76ea5e321c 160000 --- a/vcpkg +++ b/vcpkg @@ -1 +1 @@ -Subproject commit 29858b3cb2c8a0ec2c85b1b14d6d0a0d1dfe309e +Subproject commit 76ea5e321cf88cf1c99a7bd0fcebae7c8f990ee0 From ada8e57059e47727ebed8098a60fa9cbfe556cdb Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Mon, 15 Oct 2018 14:15:32 -0700 Subject: [PATCH 280/438] Correct .gitmodules to point to upstream vcpkg. --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 326611e519..3c19d8d07f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "vcpkg"] path = vcpkg - url = https://github.com/BillyONeal/vcpkg + url = https://github.com/Microsoft/vcpkg From 943c6f8370dda65c092fe0217b2358944044a6fd Mon Sep 17 00:00:00 2001 From: Randy Ramos Date: Tue, 16 Oct 2018 03:38:44 -0400 Subject: [PATCH 281/438] Add install instructions for Fedora (#919) --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 6739483ebf..391027675b 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,10 @@ With [apt-get](https://launchpad.net/ubuntu/+source/casablanca/2.8.0-2build2) on ``` $ sudo apt-get install libcpprest-dev ``` +With [dnf](https://apps.fedoraproject.org/packages/cpprest) on Fedora +``` +$ sudo dnf install cpprest-devel +``` With [brew](https://github.com/Homebrew/homebrew-core/blob/master/Formula/cpprestsdk.rb) on OSX ``` $ brew install cpprestsdk From 9c8e0d41fb6e27acb2ae0edbd08022b392c2a33c Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Tue, 16 Oct 2018 14:31:43 -0700 Subject: [PATCH 282/438] Fix off-by-one error in connection pooling introduced with asio certificate changes in 2.10.4 (#920) * Fix off-by-one error introduced in connection pool stack. This got introduced when the connection pool queue was changed into a stack to reuse hot connections. * Make connection_pool_stack testable and add tests. --- Release/src/CMakeLists.txt | 7 +- Release/src/http/client/http_client_asio.cpp | 45 +------------ .../src/http/common/connection_pool_helpers.h | 66 +++++++++++++++++++ .../functional/http/client/CMakeLists.txt | 5 +- .../http/client/connection_pool_tests.cpp | 45 +++++++++++++ 5 files changed, 120 insertions(+), 48 deletions(-) create mode 100644 Release/src/http/common/connection_pool_helpers.h create mode 100644 Release/tests/functional/http/client/connection_pool_tests.cpp diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt index eceaad7437..cea7048c7d 100644 --- a/Release/src/CMakeLists.txt +++ b/Release/src/CMakeLists.txt @@ -16,12 +16,13 @@ set(SOURCES ${HEADERS_DETAILS} pch/stdafx.h http/client/http_client.cpp - http/client/http_client_msg.cpp http/client/http_client_impl.h - http/common/internal_http_helpers.h + http/client/http_client_msg.cpp + http/common/connection_pool_helpers.h + http/common/http_compression.cpp http/common/http_helpers.cpp http/common/http_msg.cpp - http/common/http_compression.cpp + http/common/internal_http_helpers.h http/listener/http_listener.cpp http/listener/http_listener_msg.cpp http/listener/http_server_api.cpp diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp index 645b45466c..ada8e9494d 100644 --- a/Release/src/http/client/http_client_asio.cpp +++ b/Release/src/http/client/http_client_asio.cpp @@ -17,6 +17,7 @@ #include #include "../common/internal_http_helpers.h" +#include "../common/connection_pool_helpers.h" #include "cpprest/asyncrt_utils.h" #if defined(__clang__) @@ -345,48 +346,6 @@ class asio_connection bool m_closed; }; -class connection_pool_stack -{ -public: - // attempts to acquire a connection from the deque; returns nullptr if no connection is - // available - std::shared_ptr try_acquire() CPPREST_NOEXCEPT - { - const size_t oldConnectionsSize = m_connections.size(); - if (m_highWater > oldConnectionsSize) - { - m_highWater = oldConnectionsSize; - } - - if (oldConnectionsSize == 0) - { - return nullptr; - } - - auto result = std::move(m_connections.back()); - m_connections.pop_back(); - return result; - } - - // releases `released` back to the connection pool - void release(std::shared_ptr&& released) - { - m_connections.push_back(std::move(released)); - } - - bool free_stale_connections() CPPREST_NOEXCEPT - { - m_connections.erase(m_connections.begin(), m_connections.begin() + m_highWater); - const size_t connectionsSize = m_connections.size(); - m_highWater = connectionsSize; - return (connectionsSize != 0); - } - -private: - size_t m_highWater = 0; - std::vector> m_connections; -}; - /// Implements a connection pool with adaptive connection removal /// /// Every 30 seconds, the lambda in `start_epoch_interval` fires, triggering the @@ -501,7 +460,7 @@ class asio_connection_pool final : public std::enable_shared_from_this m_connections; + std::map> m_connections; bool m_is_timer_running; boost::asio::deadline_timer m_pool_epoch_timer; }; diff --git a/Release/src/http/common/connection_pool_helpers.h b/Release/src/http/common/connection_pool_helpers.h new file mode 100644 index 0000000000..580b82af23 --- /dev/null +++ b/Release/src/http/common/connection_pool_helpers.h @@ -0,0 +1,66 @@ +#pragma once + +#include "cpprest/details/cpprest_compat.h" +#include +#include +#include + +namespace web +{ +namespace http +{ +namespace client +{ +namespace details +{ + +template +class connection_pool_stack +{ +public: + // attempts to acquire a connection from the deque; returns nullptr if no connection is + // available + std::shared_ptr try_acquire() CPPREST_NOEXCEPT + { + const size_t oldConnectionsSize = m_connections.size(); + if (oldConnectionsSize == 0) + { + m_staleBefore = 0; + return nullptr; + } + + auto result = std::move(m_connections.back()); + m_connections.pop_back(); + const size_t newConnectionsSize = m_connections.size(); + if (m_staleBefore > newConnectionsSize) + { + m_staleBefore = newConnectionsSize; + } + + return result; + } + + // releases `released` back to the connection pool + void release(std::shared_ptr&& released) + { + m_connections.push_back(std::move(released)); + } + + bool free_stale_connections() CPPREST_NOEXCEPT + { + assert(m_staleBefore <= m_connections.size()); + m_connections.erase(m_connections.begin(), m_connections.begin() + m_staleBefore); + const size_t connectionsSize = m_connections.size(); + m_staleBefore = connectionsSize; + return (connectionsSize != 0); + } + +private: + std::vector> m_connections; + size_t m_staleBefore = 0; +}; + +} // details +} // client +} // http +} // web diff --git a/Release/tests/functional/http/client/CMakeLists.txt b/Release/tests/functional/http/client/CMakeLists.txt index d92b477481..45f0d9af02 100644 --- a/Release/tests/functional/http/client/CMakeLists.txt +++ b/Release/tests/functional/http/client/CMakeLists.txt @@ -2,8 +2,11 @@ set(SOURCES authentication_tests.cpp building_request_tests.cpp client_construction.cpp + compression_tests.cpp + connection_pool_tests.cpp connections_and_errors.cpp header_tests.cpp + http_client_fuzz_tests.cpp http_client_tests.cpp http_methods_tests.cpp multiple_requests.cpp @@ -20,8 +23,6 @@ set(SOURCES response_stream_tests.cpp status_code_reason_phrase_tests.cpp to_string_tests.cpp - http_client_fuzz_tests.cpp - compression_tests.cpp ) add_casablanca_test(httpclient_test SOURCES) diff --git a/Release/tests/functional/http/client/connection_pool_tests.cpp b/Release/tests/functional/http/client/connection_pool_tests.cpp new file mode 100644 index 0000000000..037ed69d88 --- /dev/null +++ b/Release/tests/functional/http/client/connection_pool_tests.cpp @@ -0,0 +1,45 @@ +#include "stdafx.h" +#include +#include "../../../src/http/common/connection_pool_helpers.h" + +using namespace web::http::client::details; + +SUITE(connection_pooling) { + TEST(empty_returns_nullptr) { + connection_pool_stack connectionStack; + VERIFY_ARE_EQUAL(connectionStack.try_acquire(), std::shared_ptr{}); + } + + static int noisyCount = 0; + struct noisy { + noisy() = delete; + noisy(int) { ++noisyCount; } + noisy(const noisy&) = delete; + noisy(noisy&&) { ++noisyCount; } + noisy& operator=(const noisy&) = delete; + noisy& operator=(noisy&&) = delete; + ~noisy() { --noisyCount; } + }; + + TEST(cycled_connections_survive) { + connection_pool_stack connectionStack; + VERIFY_ARE_EQUAL(0, noisyCount); + connectionStack.release(std::make_shared(42)); + connectionStack.release(std::make_shared(42)); + connectionStack.release(std::make_shared(42)); + VERIFY_ARE_EQUAL(3, noisyCount); + VERIFY_IS_TRUE(connectionStack.free_stale_connections()); + auto tmp = connectionStack.try_acquire(); + VERIFY_ARE_NOT_EQUAL(tmp, std::shared_ptr{}); + connectionStack.release(std::move(tmp)); + VERIFY_ARE_EQUAL(tmp, std::shared_ptr{}); + tmp = connectionStack.try_acquire(); + VERIFY_ARE_NOT_EQUAL(tmp, std::shared_ptr{}); + connectionStack.release(std::move(tmp)); + VERIFY_IS_TRUE(connectionStack.free_stale_connections()); + VERIFY_ARE_EQUAL(1, noisyCount); + VERIFY_IS_FALSE(connectionStack.free_stale_connections()); + VERIFY_ARE_EQUAL(0, noisyCount); + VERIFY_IS_FALSE(connectionStack.free_stale_connections()); + } +}; From 06619a7c4561d81190971e4431cd96924afc377d Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Tue, 16 Oct 2018 15:26:21 -0700 Subject: [PATCH 283/438] Update embedded websockets to 0.8.1 and use submodule instead of checkin (#921) * Delete checked in websocketpp. * Add submodule reference to websocketpp 0.8.1. --- .gitmodules | 3 + Release/libs/websocketpp | 1 + Release/libs/websocketpp/.gitattributes | 18 - Release/libs/websocketpp/.gitignore | 90 - Release/libs/websocketpp/.travis.yml | 23 - Release/libs/websocketpp/CMakeLists.txt | 247 -- Release/libs/websocketpp/COPYING | 145 -- Release/libs/websocketpp/Doxyfile | 1874 -------------- Release/libs/websocketpp/SConstruct | 266 -- Release/libs/websocketpp/changelog.md | 234 -- .../docs/simple_broadcast_server.cpp | 52 - .../docs/simple_count_server_thread.cpp | 65 - .../libs/websocketpp/examples/CMakeLists.txt | 6 - .../associative_storage.cpp | 88 - .../examples/broadcast_server/SConscript | 23 - .../broadcast_server/broadcast_server.cpp | 156 -- .../examples/debug_client/SConscript | 24 - .../examples/debug_client/debug_client.cpp | 166 -- .../examples/debug_server/CMakeLists.txt | 10 - .../examples/debug_server/SConscript | 23 - .../examples/debug_server/debug_server.cpp | 174 -- .../libs/websocketpp/examples/dev/SConscript | 18 - .../libs/websocketpp/examples/dev/main.cpp | 200 -- .../examples/echo_server/CMakeLists.txt | 10 - .../examples/echo_server/SConscript | 23 - .../examples/echo_server/echo_handler.hpp | 37 - .../examples/echo_server/echo_server.cpp | 58 - .../examples/echo_server_both/CMakeLists.txt | 15 - .../examples/echo_server_both/SConscript | 24 - .../echo_server_both/echo_server_both.cpp | 87 - .../examples/echo_server_both/server.pem | 58 - .../examples/echo_server_tls/CMakeLists.txt | 15 - .../examples/echo_server_tls/SConscript | 24 - .../echo_server_tls/echo_server_tls.cpp | 73 - .../examples/echo_server_tls/server.pem | 58 - .../enriched_storage/enriched_storage.cpp | 87 - .../handler_switch/handler_switch.cpp | 42 - .../examples/iostream_server/SConscript | 23 - .../iostream_server/iostream_server.cpp | 89 - .../examples/print_server/CMakeLists.txt | 10 - .../examples/print_server/SConscript | 23 - .../examples/print_server/print_server.cpp | 22 - .../simple_broadcast_server.cpp | 51 - .../examples/sip_client/CMakeLists.txt | 11 - .../examples/sip_client/README.txt | 22 - .../examples/sip_client/SConscript | 23 - .../examples/sip_client/sip_client.cpp | 84 - .../examples/subprotocol_server/SConscript | 23 - .../subprotocol_server/subprotocol_server.cpp | 48 - .../examples/telemetry_client/CMakeLists.txt | 10 - .../examples/telemetry_client/SConscript | 23 - .../telemetry_client/telemetry_client.cpp | 156 -- .../examples/telemetry_server/CMakeLists.txt | 10 - .../examples/telemetry_server/SConscript | 23 - .../examples/telemetry_server/index.html | 85 - .../telemetry_server/telemetry_server.cpp | 204 -- .../examples/testee_client/CMakeLists.txt | 11 - .../examples/testee_client/SConscript | 23 - .../examples/testee_client/testee_client.cpp | 80 - .../examples/testee_server/SConscript | 23 - .../examples/testee_server/testee_server.cpp | 138 - .../examples/utility_client/CMakeLists.txt | 11 - .../examples/utility_client/SConscript | 23 - .../utility_client/utility_client.cpp | 325 --- Release/libs/websocketpp/readme.md | 45 - Release/libs/websocketpp/roadmap.md | 43 - .../websocketpp/test/connection/SConscript | 25 - .../test/connection/connection.cpp | 478 ---- .../test/connection/connection_tu2.cpp | 62 - .../test/connection/connection_tu2.hpp | 51 - .../libs/websocketpp/test/endpoint/SConscript | 24 - .../websocketpp/test/endpoint/endpoint.cpp | 126 - .../websocketpp/test/extension/SConscript | 27 - .../websocketpp/test/extension/extension.cpp | 37 - .../test/extension/permessage_deflate.cpp | 543 ---- Release/libs/websocketpp/test/http/SConscript | 23 - Release/libs/websocketpp/test/http/parser.cpp | 1127 -------- .../websocketpp/test/http/parser_perf.cpp | 141 - .../libs/websocketpp/test/logger/SConscript | 23 - .../libs/websocketpp/test/logger/basic.cpp | 81 - .../test/message_buffer/SConscript | 27 - .../websocketpp/test/message_buffer/alloc.cpp | 96 - .../test/message_buffer/message.cpp | 72 - .../websocketpp/test/message_buffer/pool.cpp | 156 -- .../websocketpp/test/processors/SConscript | 47 - .../extension_permessage_compress.cpp | 198 -- .../websocketpp/test/processors/hybi00.cpp | 274 -- .../websocketpp/test/processors/hybi07.cpp | 193 -- .../websocketpp/test/processors/hybi08.cpp | 197 -- .../websocketpp/test/processors/hybi13.cpp | 693 ----- .../websocketpp/test/processors/processor.cpp | 135 - .../libs/websocketpp/test/random/SConscript | 27 - Release/libs/websocketpp/test/random/none.cpp | 40 - .../websocketpp/test/random/random_device.cpp | 50 - .../libs/websocketpp/test/roles/SConscript | 27 - .../libs/websocketpp/test/roles/client.cpp | 194 -- .../libs/websocketpp/test/roles/server.cpp | 247 -- .../websocketpp/test/transport/SConscript | 24 - .../test/transport/asio/SConscript | 28 - .../websocketpp/test/transport/asio/base.cpp | 49 - .../test/transport/asio/timers.cpp | 187 -- .../websocketpp/test/transport/hybi_util.cpp | 98 - .../test/transport/integration.cpp | 609 ----- .../test/transport/iostream/SConscript | 31 - .../test/transport/iostream/base.cpp | 33 - .../test/transport/iostream/connection.cpp | 575 ----- .../test/transport/iostream/endpoint.cpp | 41 - .../libs/websocketpp/test/utility/SConscript | 40 - .../libs/websocketpp/test/utility/close.cpp | 125 - .../libs/websocketpp/test/utility/error.cpp | 54 - .../libs/websocketpp/test/utility/frame.cpp | 538 ---- .../libs/websocketpp/test/utility/sha1.cpp | 81 - Release/libs/websocketpp/test/utility/uri.cpp | 246 -- .../websocketpp/test/utility/utilities.cpp | 73 - .../broadcast_tutorial/broadcast_tutorial.md | 17 - .../tutorials/chat_tutorial/chat_tutorial.md | 13 - .../tutorials/utility_client/step1.cpp | 56 - .../tutorials/utility_client/step2.cpp | 61 - .../tutorials/utility_client/step3.cpp | 81 - .../tutorials/utility_client/step4.cpp | 202 -- .../tutorials/utility_client/step5.cpp | 280 -- .../tutorials/utility_client/step6.cpp | 335 --- .../utility_client/utility_client.md | 856 ------- .../websocketpp/websocketpp-config.cmake.in | 7 - .../websocketpp-configVersion.cmake.in | 11 - .../websocketpp/websocketpp/CMakeLists.txt | 2 - .../websocketpp/websocketpp/base64/base64.hpp | 178 -- .../libs/websocketpp/websocketpp/client.hpp | 33 - .../libs/websocketpp/websocketpp/close.hpp | 342 --- .../websocketpp/websocketpp/common/chrono.hpp | 55 - .../websocketpp/common/connection_hdl.hpp | 52 - .../websocketpp/websocketpp/common/cpp11.hpp | 150 -- .../websocketpp/common/functional.hpp | 105 - .../websocketpp/websocketpp/common/md5.hpp | 448 ---- .../websocketpp/websocketpp/common/memory.hpp | 86 - .../websocketpp/common/network.hpp | 104 - .../websocketpp/common/platforms.hpp | 46 - .../websocketpp/websocketpp/common/random.hpp | 82 - .../websocketpp/websocketpp/common/regex.hpp | 59 - .../websocketpp/websocketpp/common/stdint.hpp | 73 - .../websocketpp/common/system_error.hpp | 82 - .../websocketpp/websocketpp/common/thread.hpp | 76 - .../websocketpp/websocketpp/common/time.hpp | 56 - .../websocketpp/concurrency/basic.hpp | 46 - .../websocketpp/concurrency/none.hpp | 80 - .../websocketpp/websocketpp/config/asio.hpp | 77 - .../websocketpp/config/asio_client.hpp | 77 - .../websocketpp/config/asio_no_tls.hpp | 73 - .../websocketpp/config/asio_no_tls_client.hpp | 73 - .../websocketpp/config/boost_config.hpp | 72 - .../websocketpp/websocketpp/config/core.hpp | 285 --- .../websocketpp/config/core_client.hpp | 294 --- .../websocketpp/websocketpp/config/debug.hpp | 286 --- .../websocketpp/config/debug_asio.hpp | 77 - .../websocketpp/config/debug_asio_no_tls.hpp | 73 - .../websocketpp/config/minimal_client.hpp | 72 - .../websocketpp/config/minimal_server.hpp | 312 --- .../websocketpp/websocketpp/connection.hpp | 1537 ----------- .../websocketpp/connection_base.hpp | 38 - .../libs/websocketpp/websocketpp/endpoint.hpp | 619 ----- .../websocketpp/websocketpp/endpoint_base.hpp | 38 - .../libs/websocketpp/websocketpp/error.hpp | 272 -- .../websocketpp/error_container.hpp | 71 - .../websocketpp/extensions/extension.hpp | 102 - .../permessage_deflate/disabled.hpp | 106 - .../extensions/permessage_deflate/enabled.hpp | 725 ------ .../libs/websocketpp/websocketpp/frame.hpp | 863 ------- .../websocketpp/http/constants.hpp | 308 --- .../websocketpp/http/impl/parser.hpp | 196 -- .../websocketpp/http/impl/request.hpp | 191 -- .../websocketpp/http/impl/response.hpp | 266 -- .../websocketpp/websocketpp/http/parser.hpp | 615 ----- .../websocketpp/websocketpp/http/request.hpp | 124 - .../websocketpp/websocketpp/http/response.hpp | 188 -- .../websocketpp/impl/connection_impl.hpp | 2267 ----------------- .../websocketpp/impl/endpoint_impl.hpp | 255 -- .../websocketpp/impl/utilities_impl.hpp | 87 - .../websocketpp/websocketpp/logger/basic.hpp | 169 -- .../websocketpp/websocketpp/logger/levels.hpp | 203 -- .../websocketpp/websocketpp/logger/stub.hpp | 119 - .../websocketpp/websocketpp/logger/syslog.hpp | 146 -- .../websocketpp/message_buffer/alloc.hpp | 105 - .../websocketpp/message_buffer/message.hpp | 340 --- .../websocketpp/message_buffer/pool.hpp | 229 -- .../websocketpp/processors/base.hpp | 299 --- .../websocketpp/processors/hybi00.hpp | 448 ---- .../websocketpp/processors/hybi07.hpp | 78 - .../websocketpp/processors/hybi08.hpp | 83 - .../websocketpp/processors/hybi13.hpp | 1005 -------- .../websocketpp/processors/processor.hpp | 392 --- .../websocketpp/websocketpp/random/none.hpp | 60 - .../websocketpp/random/random_device.hpp | 80 - .../websocketpp/roles/client_endpoint.hpp | 170 -- .../websocketpp/roles/server_endpoint.hpp | 166 -- .../libs/websocketpp/websocketpp/server.hpp | 33 - .../websocketpp/websocketpp/sha1/sha1.hpp | 189 -- .../websocketpp/transport/asio/base.hpp | 251 -- .../websocketpp/transport/asio/connection.hpp | 1162 --------- .../websocketpp/transport/asio/endpoint.hpp | 1094 -------- .../transport/asio/security/base.hpp | 152 -- .../transport/asio/security/none.hpp | 329 --- .../transport/asio/security/tls.hpp | 426 ---- .../websocketpp/transport/base/connection.hpp | 238 -- .../websocketpp/transport/base/endpoint.hpp | 77 - .../websocketpp/transport/debug/base.hpp | 104 - .../transport/debug/connection.hpp | 397 --- .../websocketpp/transport/debug/endpoint.hpp | 140 - .../websocketpp/transport/iostream/base.hpp | 121 - .../transport/iostream/connection.hpp | 661 ----- .../transport/iostream/endpoint.hpp | 222 -- .../websocketpp/transport/stub/base.hpp | 95 - .../websocketpp/transport/stub/connection.hpp | 272 -- .../websocketpp/transport/stub/endpoint.hpp | 140 - Release/libs/websocketpp/websocketpp/uri.hpp | 354 --- .../websocketpp/utf8_validator.hpp | 154 -- .../websocketpp/websocketpp/utilities.hpp | 182 -- .../libs/websocketpp/websocketpp/version.hpp | 60 - 217 files changed, 4 insertions(+), 40106 deletions(-) create mode 160000 Release/libs/websocketpp delete mode 100644 Release/libs/websocketpp/.gitattributes delete mode 100644 Release/libs/websocketpp/.gitignore delete mode 100644 Release/libs/websocketpp/.travis.yml delete mode 100644 Release/libs/websocketpp/CMakeLists.txt delete mode 100644 Release/libs/websocketpp/COPYING delete mode 100644 Release/libs/websocketpp/Doxyfile delete mode 100644 Release/libs/websocketpp/SConstruct delete mode 100644 Release/libs/websocketpp/changelog.md delete mode 100644 Release/libs/websocketpp/docs/simple_broadcast_server.cpp delete mode 100644 Release/libs/websocketpp/docs/simple_count_server_thread.cpp delete mode 100644 Release/libs/websocketpp/examples/CMakeLists.txt delete mode 100644 Release/libs/websocketpp/examples/associative_storage/associative_storage.cpp delete mode 100644 Release/libs/websocketpp/examples/broadcast_server/SConscript delete mode 100644 Release/libs/websocketpp/examples/broadcast_server/broadcast_server.cpp delete mode 100644 Release/libs/websocketpp/examples/debug_client/SConscript delete mode 100644 Release/libs/websocketpp/examples/debug_client/debug_client.cpp delete mode 100644 Release/libs/websocketpp/examples/debug_server/CMakeLists.txt delete mode 100644 Release/libs/websocketpp/examples/debug_server/SConscript delete mode 100644 Release/libs/websocketpp/examples/debug_server/debug_server.cpp delete mode 100644 Release/libs/websocketpp/examples/dev/SConscript delete mode 100644 Release/libs/websocketpp/examples/dev/main.cpp delete mode 100644 Release/libs/websocketpp/examples/echo_server/CMakeLists.txt delete mode 100644 Release/libs/websocketpp/examples/echo_server/SConscript delete mode 100644 Release/libs/websocketpp/examples/echo_server/echo_handler.hpp delete mode 100644 Release/libs/websocketpp/examples/echo_server/echo_server.cpp delete mode 100644 Release/libs/websocketpp/examples/echo_server_both/CMakeLists.txt delete mode 100644 Release/libs/websocketpp/examples/echo_server_both/SConscript delete mode 100644 Release/libs/websocketpp/examples/echo_server_both/echo_server_both.cpp delete mode 100644 Release/libs/websocketpp/examples/echo_server_both/server.pem delete mode 100644 Release/libs/websocketpp/examples/echo_server_tls/CMakeLists.txt delete mode 100644 Release/libs/websocketpp/examples/echo_server_tls/SConscript delete mode 100644 Release/libs/websocketpp/examples/echo_server_tls/echo_server_tls.cpp delete mode 100644 Release/libs/websocketpp/examples/echo_server_tls/server.pem delete mode 100644 Release/libs/websocketpp/examples/enriched_storage/enriched_storage.cpp delete mode 100644 Release/libs/websocketpp/examples/handler_switch/handler_switch.cpp delete mode 100644 Release/libs/websocketpp/examples/iostream_server/SConscript delete mode 100644 Release/libs/websocketpp/examples/iostream_server/iostream_server.cpp delete mode 100644 Release/libs/websocketpp/examples/print_server/CMakeLists.txt delete mode 100644 Release/libs/websocketpp/examples/print_server/SConscript delete mode 100644 Release/libs/websocketpp/examples/print_server/print_server.cpp delete mode 100644 Release/libs/websocketpp/examples/simple_broadcast_server/simple_broadcast_server.cpp delete mode 100644 Release/libs/websocketpp/examples/sip_client/CMakeLists.txt delete mode 100644 Release/libs/websocketpp/examples/sip_client/README.txt delete mode 100644 Release/libs/websocketpp/examples/sip_client/SConscript delete mode 100644 Release/libs/websocketpp/examples/sip_client/sip_client.cpp delete mode 100644 Release/libs/websocketpp/examples/subprotocol_server/SConscript delete mode 100644 Release/libs/websocketpp/examples/subprotocol_server/subprotocol_server.cpp delete mode 100644 Release/libs/websocketpp/examples/telemetry_client/CMakeLists.txt delete mode 100644 Release/libs/websocketpp/examples/telemetry_client/SConscript delete mode 100644 Release/libs/websocketpp/examples/telemetry_client/telemetry_client.cpp delete mode 100644 Release/libs/websocketpp/examples/telemetry_server/CMakeLists.txt delete mode 100644 Release/libs/websocketpp/examples/telemetry_server/SConscript delete mode 100644 Release/libs/websocketpp/examples/telemetry_server/index.html delete mode 100644 Release/libs/websocketpp/examples/telemetry_server/telemetry_server.cpp delete mode 100644 Release/libs/websocketpp/examples/testee_client/CMakeLists.txt delete mode 100644 Release/libs/websocketpp/examples/testee_client/SConscript delete mode 100644 Release/libs/websocketpp/examples/testee_client/testee_client.cpp delete mode 100644 Release/libs/websocketpp/examples/testee_server/SConscript delete mode 100644 Release/libs/websocketpp/examples/testee_server/testee_server.cpp delete mode 100644 Release/libs/websocketpp/examples/utility_client/CMakeLists.txt delete mode 100644 Release/libs/websocketpp/examples/utility_client/SConscript delete mode 100644 Release/libs/websocketpp/examples/utility_client/utility_client.cpp delete mode 100644 Release/libs/websocketpp/readme.md delete mode 100644 Release/libs/websocketpp/roadmap.md delete mode 100644 Release/libs/websocketpp/test/connection/SConscript delete mode 100644 Release/libs/websocketpp/test/connection/connection.cpp delete mode 100644 Release/libs/websocketpp/test/connection/connection_tu2.cpp delete mode 100644 Release/libs/websocketpp/test/connection/connection_tu2.hpp delete mode 100644 Release/libs/websocketpp/test/endpoint/SConscript delete mode 100644 Release/libs/websocketpp/test/endpoint/endpoint.cpp delete mode 100644 Release/libs/websocketpp/test/extension/SConscript delete mode 100644 Release/libs/websocketpp/test/extension/extension.cpp delete mode 100644 Release/libs/websocketpp/test/extension/permessage_deflate.cpp delete mode 100644 Release/libs/websocketpp/test/http/SConscript delete mode 100644 Release/libs/websocketpp/test/http/parser.cpp delete mode 100644 Release/libs/websocketpp/test/http/parser_perf.cpp delete mode 100644 Release/libs/websocketpp/test/logger/SConscript delete mode 100644 Release/libs/websocketpp/test/logger/basic.cpp delete mode 100644 Release/libs/websocketpp/test/message_buffer/SConscript delete mode 100644 Release/libs/websocketpp/test/message_buffer/alloc.cpp delete mode 100644 Release/libs/websocketpp/test/message_buffer/message.cpp delete mode 100644 Release/libs/websocketpp/test/message_buffer/pool.cpp delete mode 100644 Release/libs/websocketpp/test/processors/SConscript delete mode 100644 Release/libs/websocketpp/test/processors/extension_permessage_compress.cpp delete mode 100644 Release/libs/websocketpp/test/processors/hybi00.cpp delete mode 100644 Release/libs/websocketpp/test/processors/hybi07.cpp delete mode 100644 Release/libs/websocketpp/test/processors/hybi08.cpp delete mode 100644 Release/libs/websocketpp/test/processors/hybi13.cpp delete mode 100644 Release/libs/websocketpp/test/processors/processor.cpp delete mode 100644 Release/libs/websocketpp/test/random/SConscript delete mode 100644 Release/libs/websocketpp/test/random/none.cpp delete mode 100644 Release/libs/websocketpp/test/random/random_device.cpp delete mode 100644 Release/libs/websocketpp/test/roles/SConscript delete mode 100644 Release/libs/websocketpp/test/roles/client.cpp delete mode 100644 Release/libs/websocketpp/test/roles/server.cpp delete mode 100644 Release/libs/websocketpp/test/transport/SConscript delete mode 100644 Release/libs/websocketpp/test/transport/asio/SConscript delete mode 100644 Release/libs/websocketpp/test/transport/asio/base.cpp delete mode 100644 Release/libs/websocketpp/test/transport/asio/timers.cpp delete mode 100644 Release/libs/websocketpp/test/transport/hybi_util.cpp delete mode 100644 Release/libs/websocketpp/test/transport/integration.cpp delete mode 100644 Release/libs/websocketpp/test/transport/iostream/SConscript delete mode 100644 Release/libs/websocketpp/test/transport/iostream/base.cpp delete mode 100644 Release/libs/websocketpp/test/transport/iostream/connection.cpp delete mode 100644 Release/libs/websocketpp/test/transport/iostream/endpoint.cpp delete mode 100644 Release/libs/websocketpp/test/utility/SConscript delete mode 100644 Release/libs/websocketpp/test/utility/close.cpp delete mode 100644 Release/libs/websocketpp/test/utility/error.cpp delete mode 100644 Release/libs/websocketpp/test/utility/frame.cpp delete mode 100644 Release/libs/websocketpp/test/utility/sha1.cpp delete mode 100644 Release/libs/websocketpp/test/utility/uri.cpp delete mode 100644 Release/libs/websocketpp/test/utility/utilities.cpp delete mode 100644 Release/libs/websocketpp/tutorials/broadcast_tutorial/broadcast_tutorial.md delete mode 100644 Release/libs/websocketpp/tutorials/chat_tutorial/chat_tutorial.md delete mode 100644 Release/libs/websocketpp/tutorials/utility_client/step1.cpp delete mode 100644 Release/libs/websocketpp/tutorials/utility_client/step2.cpp delete mode 100644 Release/libs/websocketpp/tutorials/utility_client/step3.cpp delete mode 100644 Release/libs/websocketpp/tutorials/utility_client/step4.cpp delete mode 100644 Release/libs/websocketpp/tutorials/utility_client/step5.cpp delete mode 100644 Release/libs/websocketpp/tutorials/utility_client/step6.cpp delete mode 100644 Release/libs/websocketpp/tutorials/utility_client/utility_client.md delete mode 100644 Release/libs/websocketpp/websocketpp-config.cmake.in delete mode 100644 Release/libs/websocketpp/websocketpp-configVersion.cmake.in delete mode 100644 Release/libs/websocketpp/websocketpp/CMakeLists.txt delete mode 100644 Release/libs/websocketpp/websocketpp/base64/base64.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/client.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/close.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/common/chrono.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/common/connection_hdl.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/common/cpp11.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/common/functional.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/common/md5.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/common/memory.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/common/network.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/common/platforms.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/common/random.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/common/regex.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/common/stdint.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/common/system_error.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/common/thread.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/common/time.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/concurrency/basic.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/concurrency/none.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/config/asio.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/config/asio_client.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/config/asio_no_tls.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/config/asio_no_tls_client.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/config/boost_config.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/config/core.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/config/core_client.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/config/debug.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/config/debug_asio.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/config/debug_asio_no_tls.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/config/minimal_client.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/config/minimal_server.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/connection.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/connection_base.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/endpoint.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/endpoint_base.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/error.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/error_container.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/extensions/extension.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/extensions/permessage_deflate/disabled.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/frame.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/http/constants.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/http/impl/parser.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/http/impl/request.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/http/impl/response.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/http/parser.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/http/request.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/http/response.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/impl/connection_impl.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/impl/endpoint_impl.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/impl/utilities_impl.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/logger/basic.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/logger/levels.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/logger/stub.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/logger/syslog.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/message_buffer/alloc.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/message_buffer/message.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/message_buffer/pool.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/processors/base.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/processors/hybi00.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/processors/hybi07.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/processors/hybi08.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/processors/hybi13.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/processors/processor.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/random/none.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/random/random_device.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/roles/client_endpoint.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/roles/server_endpoint.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/server.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/sha1/sha1.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/asio/base.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/asio/connection.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/asio/endpoint.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/asio/security/base.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/asio/security/none.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/base/connection.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/base/endpoint.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/debug/base.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/debug/connection.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/debug/endpoint.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/iostream/base.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/iostream/connection.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/iostream/endpoint.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/stub/base.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/stub/connection.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/transport/stub/endpoint.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/uri.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/utf8_validator.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/utilities.hpp delete mode 100644 Release/libs/websocketpp/websocketpp/version.hpp diff --git a/.gitmodules b/.gitmodules index 3c19d8d07f..5a33829602 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "vcpkg"] path = vcpkg url = https://github.com/Microsoft/vcpkg +[submodule "websocketspp"] + path = Release/libs/websocketpp + url = https://github.com/zaphoyd/websocketpp/ diff --git a/Release/libs/websocketpp b/Release/libs/websocketpp new file mode 160000 index 0000000000..c6d7e295bf --- /dev/null +++ b/Release/libs/websocketpp @@ -0,0 +1 @@ +Subproject commit c6d7e295bf5a0ab9b5f896720cc1a0e0fdc397a7 diff --git a/Release/libs/websocketpp/.gitattributes b/Release/libs/websocketpp/.gitattributes deleted file mode 100644 index a9e4fc784b..0000000000 --- a/Release/libs/websocketpp/.gitattributes +++ /dev/null @@ -1,18 +0,0 @@ -# Lineendings -*.sln eol=crlf -*.vcproj eol=crlf -*.vcxproj* eol=crlf - -# Whitespace rules -# strict (no trailing, no tabs) -*.cpp whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol -*.hpp whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol -*.c whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol -*.h whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol - -# normal (no trailing) -*.sql whitespace=trailing-space,space-before-tab,cr-at-eol -*.txt whitespace=trailing-space,space-before-tab,cr-at-eol - -# special files which must ignore whitespace -*.patch whitespace=-trailing-space diff --git a/Release/libs/websocketpp/.gitignore b/Release/libs/websocketpp/.gitignore deleted file mode 100644 index 558a1b3d7f..0000000000 --- a/Release/libs/websocketpp/.gitignore +++ /dev/null @@ -1,90 +0,0 @@ -# make .git* files visible to git -!.gitignore -!.gitattributes - -.DS_Store - -#vim stuff -*~ -*.swp - -*.o -*.so -*.so.? -*.so.?.?.? -*.a -*.dylib -lib/* - -# CMake -*.cmake -*.dir -CMakeFiles -INSTALL.* -ZERO_CHECK.* -CMakeCache.txt -install_manifest.txt - -# Windows/Visual Studio -*.vcproj* -*.sln -*.suo -*.ncb -*/Debug/* -*/*/Debug/* -bin/Debug -*/Release/* -*/*/Release/* -*/RelWithDebInfo/* -*/*/RelWithDebInfo/* - -# explicitly allow this path with /debug/ in it -!websocketpp/transport/debug/* - -objs_shared/ -objs_static/ - -examples/chat_server/chat_server -examples/echo_server/echo_server -examples/chat_client/chat_client -examples/echo_client/echo_client -test/basic/tests -libwebsocketpp.dylib.0.1.0 - -websocketpp.xcodeproj/xcuserdata/* -websocketpp.xcodeproj/project.xcworkspace/xcuserdata/* -policy_based_notes.hpp - -examples/echo_server_tls/echo_server_tls - -examples/fuzzing_client/fuzzing_client - -examples/stress_client/stress_client - -examples/broadcast_server_tls/broadcast_server - -test/basic/perf - -examples/echo_server_tls/echo_server_tls - -examples/concurrent_server/concurrent_server - -examples/fuzzing_server_tls/fuzzing_server - -examples/wsperf/wsperf - -.sconsign.dblite - -build/ -doxygen/ -examples/wsperf/wsperf_client - -*.out - -*.log -*.opensdf -*.sdf -*.vcxproj -*.vcxproj.filters -*.user -install diff --git a/Release/libs/websocketpp/.travis.yml b/Release/libs/websocketpp/.travis.yml deleted file mode 100644 index 027ac560ed..0000000000 --- a/Release/libs/websocketpp/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -language: cpp -compiler: - - gcc -before_install: - - sudo apt-get install libboost-regex1.48-dev libboost-system1.48-dev libboost-thread1.48-dev libboost-test1.48-dev libboost-random1.48-dev -y -env: - global: - - BOOST_INCLUDES=/usr/include - - BOOST_LIBS=/usr/lib -script: scons -j 2 && scons test -branches: - only: - - master - - permessage-deflate - - experimental - - 0.3.x-cmake - - develop -notifications: - recipients: - - travis@zaphoyd.com - email: - on_success: change - on_failure: always diff --git a/Release/libs/websocketpp/CMakeLists.txt b/Release/libs/websocketpp/CMakeLists.txt deleted file mode 100644 index f8df9de08a..0000000000 --- a/Release/libs/websocketpp/CMakeLists.txt +++ /dev/null @@ -1,247 +0,0 @@ - -############ Setup project and cmake - -# Project name -project (websocketpp) - -# Minimum cmake requirement. We should require a quite recent -# cmake for the dependency find macros etc. to be up to date. -cmake_minimum_required (VERSION 2.6) - -set (WEBSOCKETPP_MAJOR_VERSION 0) -set (WEBSOCKETPP_MINOR_VERSION 5) -set (WEBSOCKETPP_PATCH_VERSION 1) -set (WEBSOCKETPP_VERSION ${WEBSOCKETPP_MAJOR_VERSION}.${WEBSOCKETPP_MINOR_VERSION}.${WEBSOCKETPP_PATCH_VERSION}) - -set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files") -if (WIN32 AND NOT CYGWIN) - set (DEF_INSTALL_CMAKE_DIR cmake) -else () - set (DEF_INSTALL_CMAKE_DIR lib/cmake/websocketpp) -endif () -set (INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files") - -# Make relative paths absolute (needed later on) -foreach (p INCLUDE CMAKE) - set (var INSTALL_${p}_DIR) - if (NOT IS_ABSOLUTE "${${var}}") - set (${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") - endif () -endforeach () - -# Set CMake library search policy -if (COMMAND cmake_policy) - cmake_policy (SET CMP0003 NEW) - cmake_policy (SET CMP0005 NEW) -endif () - -# Disable unnecessary build types -set (CMAKE_CONFIGURATION_TYPES "Release;RelWithDebInfo;Debug" CACHE STRING "Configurations" FORCE) - -# Include our cmake macros -set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) -include (CMakeHelpers) - -############ Paths - -set (WEBSOCKETPP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) -set (WEBSOCKETPP_INCLUDE ${WEBSOCKETPP_ROOT}/websocketpp) -set (WEBSOCKETPP_BUILD_ROOT ${CMAKE_CURRENT_BINARY_DIR}) -set (WEBSOCKETPP_BIN ${WEBSOCKETPP_BUILD_ROOT}/bin) -set (WEBSOCKETPP_LIB ${WEBSOCKETPP_BUILD_ROOT}/lib) - -# CMake install step prefix. I assume linux users want the prefix to -# be the default /usr or /usr/local so this is only adjusted on Windows. -# - Windows: Build the INSTALL project in your solution file. -# - Linux/OSX: make install. -if (MSVC) - set (CMAKE_INSTALL_PREFIX "${WEBSOCKETPP_ROOT}/install") -endif () - -############ Build customization - -# Override from command line "CMake -D