diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core')
226 files changed, 38875 insertions, 0 deletions
diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/.yandex_meta/licenses.list.txt b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/.yandex_meta/licenses.list.txt new file mode 100644 index 0000000000..7bb262fe60 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/.yandex_meta/licenses.list.txt @@ -0,0 +1,254 @@ +====================Apache-2.0==================== + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. + +====================Apache-2.0==================== + * SPDX-License-Identifier: Apache-2.0. + + +====================COPYRIGHT==================== + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + +====================COPYRIGHT==================== + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + + +====================MIT==================== + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + +====================Zlib==================== +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/AmazonSerializableWebServiceRequest.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/AmazonSerializableWebServiceRequest.h new file mode 100644 index 0000000000..2ba298546e --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/AmazonSerializableWebServiceRequest.h @@ -0,0 +1,56 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/AmazonWebServiceRequest.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/UnreferencedParam.h> +#include <aws/core/http/HttpTypes.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> + +namespace Aws +{ + static const char JSON_CONTENT_TYPE[] = "application/json"; + static const char AMZN_JSON_CONTENT_TYPE_1_0[] = "application/x-amz-json-1.0"; + static const char AMZN_JSON_CONTENT_TYPE_1_1[] = "application/x-amz-json-1.1"; + static const char FORM_CONTENT_TYPE[] = "application/x-www-form-urlencoded"; + static const char AMZN_XML_CONTENT_TYPE[] = "application/xml"; + static const char AMZN_EVENTSTREAM_CONTENT_TYPE[] = "application/vnd.amazon.eventstream"; + + /** + * High-level abstraction over AWS requests. GetBody() calls SerializePayload() and uses a stringbuf under the hood. + * This is for payloads such as query, xml, or json + */ + class AWS_CORE_API AmazonSerializableWebServiceRequest : public AmazonWebServiceRequest + { + public: + AmazonSerializableWebServiceRequest() + { + //prevent unreferenced var warnings + //for these values. + AWS_UNREFERENCED_PARAM(JSON_CONTENT_TYPE); + AWS_UNREFERENCED_PARAM(AMZN_JSON_CONTENT_TYPE_1_0); + AWS_UNREFERENCED_PARAM(AMZN_JSON_CONTENT_TYPE_1_1); + AWS_UNREFERENCED_PARAM(FORM_CONTENT_TYPE); + AWS_UNREFERENCED_PARAM(AMZN_XML_CONTENT_TYPE); + } + + virtual ~AmazonSerializableWebServiceRequest() {} + + /** + * Convert payload into String. + */ + virtual Aws::String SerializePayload() const = 0; + + /** + * Loads serialized payload into string buf and returns the stream + */ + std::shared_ptr<Aws::IOStream> GetBody() const override; + }; + +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/AmazonStreamingWebServiceRequest.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/AmazonStreamingWebServiceRequest.h new file mode 100644 index 0000000000..c267d06aaf --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/AmazonStreamingWebServiceRequest.h @@ -0,0 +1,83 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/utils/UnreferencedParam.h> +#include <aws/core/http/HttpTypes.h> +#include <aws/core/http/HttpRequest.h> +#include <aws/core/AmazonWebServiceRequest.h> + +namespace Aws +{ + static const char* DEFAULT_CONTENT_TYPE = "binary/octet-stream"; + + /** + * High-level abstraction over AWS requests that don't have well formed payloads. GetBody() uses an underlying stream that has been set by a call to SetBody() + * Also supports request specific headers such as in rest protocols. + */ + class AWS_CORE_API AmazonStreamingWebServiceRequest : public AmazonWebServiceRequest + { + public: + /** + * Initializes members to defaults + */ + AmazonStreamingWebServiceRequest() : m_contentType(DEFAULT_CONTENT_TYPE) + { + } + + virtual ~AmazonStreamingWebServiceRequest(); + + /** + * Get the user set stream + */ + inline std::shared_ptr<Aws::IOStream> GetBody() const override { return m_bodyStream; } + /** + * Set the body stream to use for the request. + */ + inline void SetBody(const std::shared_ptr<Aws::IOStream>& body) { m_bodyStream = body; } + /** + * Gets all headers that will be needed in the request. Calls GetRequestSpecificHeaders(), which is the chance for subclasses to add + * headers from their modeled data. + */ + inline Aws::Http::HeaderValueCollection GetHeaders() const override + { + auto headers = GetRequestSpecificHeaders(); + headers.insert(Aws::Http::HeaderValuePair(Aws::Http::CONTENT_TYPE_HEADER, GetContentType())); + + return headers; + } + + /** + * AmazonStreamingWebServiceRequest always returns true. + */ + bool IsStreaming() const override { return true; } + + /** + * Get the user set contentType. Defaults to binary/octet-stream + */ + const Aws::String& GetContentType() const { return m_contentType; } + /** + * Set the content type. + */ + void SetContentType(const Aws::String& contentType) { m_contentType = contentType; } + + protected: + /** + * Override this method to put data members from a subclass into the headers collection. + */ + virtual Aws::Http::HeaderValueCollection GetRequestSpecificHeaders() const { return Aws::Http::HeaderValueCollection(); }; + + private: + std::shared_ptr<Aws::IOStream> m_bodyStream; + Aws::String m_contentType; + }; + +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/AmazonWebServiceRequest.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/AmazonWebServiceRequest.h new file mode 100644 index 0000000000..1fc7c0e7e0 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/AmazonWebServiceRequest.h @@ -0,0 +1,173 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/UnreferencedParam.h> +#include <aws/core/http/HttpTypes.h> +#include <aws/core/http/HttpRequest.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/utils/stream/ResponseStream.h> +#include <aws/core/auth/AWSAuthSigner.h> + +namespace Aws +{ + namespace Http + { + class URI; + } // namespace Http + + class AmazonWebServiceRequest; + + /** + * Closure definition for handling a retry notification. This is only for if you want to be notified that a particular request is being retried. + */ + typedef std::function<void(const AmazonWebServiceRequest&)> RequestRetryHandler; + typedef std::function<void(const Aws::Http::HttpRequest&)> RequestSignedHandler; + + /** + * Base level abstraction for all modeled AWS requests + */ + class AWS_CORE_API AmazonWebServiceRequest + { + public: + /** + * Sets up default response stream factory. initializes other pointers to nullptr. + */ + AmazonWebServiceRequest(); + virtual ~AmazonWebServiceRequest() = default; + + /** + * Get the payload for the request + */ + virtual std::shared_ptr<Aws::IOStream> GetBody() const = 0; + /** + * Get the headers for the request + */ + virtual Aws::Http::HeaderValueCollection GetHeaders() const = 0; + /** + * Do nothing virtual, override this to add query strings to the request + */ + virtual void AddQueryStringParameters(Aws::Http::URI& uri) const { AWS_UNREFERENCED_PARAM(uri); } + + /** + * Put the request to a url for later presigning. This will push the body to the url and + * then adds the existing query string parameters as normal. + */ + virtual void PutToPresignedUrl(Aws::Http::URI& uri) const { DumpBodyToUrl(uri); AddQueryStringParameters(uri); } + + /** + * Defaults to false, if this is set to true, it's a streaming request, which means the payload is not well structured bits. + */ + virtual bool IsStreaming() const { return false; } + + /** + * Defaults to false, if this is set to true in derived class, it's an event stream request, which means the payload is consisted by multiple structured events. + */ + inline virtual bool IsEventStreamRequest() const { return false; } + /** + * Defaults to true, if this is set to false, then signers, if they support body signing, will not do so + */ + virtual bool SignBody() const { return true; } + + /** + * Defaults to false, if this is set to true, it supports chunked transfer encoding. + */ + virtual bool IsChunked() const { return false; } + + /** + * Register closure for request signed event. + */ + inline virtual void SetRequestSignedHandler(const RequestSignedHandler& handler) { m_onRequestSigned = handler; } + /** + * Get closure for request signed event. + */ + inline virtual const RequestSignedHandler& GetRequestSignedHandler() const { return m_onRequestSigned; } + + /** + * Retrieves the factory for creating response streams. + */ + const Aws::IOStreamFactory& GetResponseStreamFactory() const { return m_responseStreamFactory; } + /** + * Set the response stream factory. + */ + void SetResponseStreamFactory(const Aws::IOStreamFactory& factory) { m_responseStreamFactory = factory; } + /** + * Register closure for data received event. + */ + inline virtual void SetDataReceivedEventHandler(const Aws::Http::DataReceivedEventHandler& dataReceivedEventHandler) { m_onDataReceived = dataReceivedEventHandler; } + /** + * register closure for data sent event + */ + inline virtual void SetDataSentEventHandler(const Aws::Http::DataSentEventHandler& dataSentEventHandler) { m_onDataSent = dataSentEventHandler; } + /** + * Register closure for handling whether or not to continue a request. + */ + inline virtual void SetContinueRequestHandler(const Aws::Http::ContinueRequestHandler& continueRequestHandler) { m_continueRequest = continueRequestHandler; } + /** + * Register closure for data received event. + */ + inline virtual void SetDataReceivedEventHandler(Aws::Http::DataReceivedEventHandler&& dataReceivedEventHandler) { m_onDataReceived = std::move(dataReceivedEventHandler); } + /** + * register closure for data sent event + */ + inline virtual void SetDataSentEventHandler(Aws::Http::DataSentEventHandler&& dataSentEventHandler) { m_onDataSent = std::move(dataSentEventHandler); } + /** + * Register closure for handling whether or not to cancel a request. + */ + inline virtual void SetContinueRequestHandler(Aws::Http::ContinueRequestHandler&& continueRequestHandler) { m_continueRequest = std::move(continueRequestHandler); } + /** + * Register closure for notification that a request is being retried + */ + inline virtual void SetRequestRetryHandler(const RequestRetryHandler& handler) { m_requestRetryHandler = handler; } + /** + * Register closure for notification that a request is being retried + */ + inline virtual void SetRequestRetryHandler(RequestRetryHandler&& handler) { m_requestRetryHandler = std::move(handler); } + /** + * get closure for data received event. + */ + inline virtual const Aws::Http::DataReceivedEventHandler& GetDataReceivedEventHandler() const { return m_onDataReceived; } + /** + * get closure for data sent event + */ + inline virtual const Aws::Http::DataSentEventHandler& GetDataSentEventHandler() const { return m_onDataSent; } + /** + * get closure for handling whether or not to cancel a request. + */ + inline virtual const Aws::Http::ContinueRequestHandler& GetContinueRequestHandler() const { return m_continueRequest; } + /** + * get closure for notification that a request is being retried + */ + inline virtual const RequestRetryHandler& GetRequestRetryHandler() const { return m_requestRetryHandler; } + /** + * If this is set to true, content-md5 needs to be computed and set on the request + */ + inline virtual bool ShouldComputeContentMd5() const { return false; } + + virtual const char* GetServiceRequestName() const = 0; + + protected: + /** + * Default does nothing. Override this to convert what would otherwise be the payload of the + * request to a query string format. + */ + virtual void DumpBodyToUrl(Aws::Http::URI& uri) const { AWS_UNREFERENCED_PARAM(uri); } + + private: + Aws::IOStreamFactory m_responseStreamFactory; + + Aws::Http::DataReceivedEventHandler m_onDataReceived; + Aws::Http::DataSentEventHandler m_onDataSent; + Aws::Http::ContinueRequestHandler m_continueRequest; + RequestSignedHandler m_onRequestSigned; + RequestRetryHandler m_requestRetryHandler; + }; + +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/AmazonWebServiceResult.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/AmazonWebServiceResult.h new file mode 100644 index 0000000000..cde25d80f6 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/AmazonWebServiceResult.h @@ -0,0 +1,77 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/http/HttpTypes.h> +#include <utility> +#include <aws/core/http/HttpResponse.h> + +namespace Aws +{ + /** + * Container for web response to an AWS Request. + */ + template <typename PAYLOAD_TYPE> + class AmazonWebServiceResult + { + public: + AmazonWebServiceResult() : m_responseCode(Http::HttpResponseCode::REQUEST_NOT_MADE) {} + + /** + * Sets payload, header collection and a response code. + */ + AmazonWebServiceResult(const PAYLOAD_TYPE& payload, const Http::HeaderValueCollection& headers, Http::HttpResponseCode responseCode = Http::HttpResponseCode::OK) : + m_payload(payload), + m_responseHeaders(headers), + m_responseCode(responseCode) + {} + + /** + * Sets payload, header collection and a response code, but transfers ownership of payload and headers (for move only operations). + */ + AmazonWebServiceResult(PAYLOAD_TYPE&& payload, Http::HeaderValueCollection&& headers, Http::HttpResponseCode responseCode = Http::HttpResponseCode::OK) : + m_payload(std::forward<PAYLOAD_TYPE>(payload)), + m_responseHeaders(std::forward<Http::HeaderValueCollection>(headers)), + m_responseCode(responseCode) + {} + + AmazonWebServiceResult(const AmazonWebServiceResult& result) : + m_payload(result.m_payload), + m_responseHeaders(result.m_responseHeaders), + m_responseCode(result.m_responseCode) + {} + + AmazonWebServiceResult(AmazonWebServiceResult&& result) : + m_payload(std::move(result.m_payload)), + m_responseHeaders(std::move(result.m_responseHeaders)), + m_responseCode(result.m_responseCode) + {} + + /** + * Get the payload from the response + */ + inline const PAYLOAD_TYPE& GetPayload() const { return m_payload; } + /** + * Get the payload from the response and take ownership of it. + */ + inline PAYLOAD_TYPE TakeOwnershipOfPayload() { return std::move(m_payload); } + /** + * Get the headers from the response + */ + inline const Http::HeaderValueCollection& GetHeaderValueCollection() const { return m_responseHeaders; } + /** + * Get the http response code from the response + */ + inline Http::HttpResponseCode GetResponseCode() const { return m_responseCode; } + + private: + PAYLOAD_TYPE m_payload; + Http::HeaderValueCollection m_responseHeaders; + Http::HttpResponseCode m_responseCode; + }; + + +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/Aws.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/Aws.h new file mode 100644 index 0000000000..4fcdb17779 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/Aws.h @@ -0,0 +1,262 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include <aws/core/utils/logging/LogLevel.h> +#include <aws/core/utils/logging/LogSystemInterface.h> +#include <aws/core/utils/memory/MemorySystemInterface.h> +#include <aws/core/utils/crypto/Factories.h> +#include <aws/core/http/HttpClientFactory.h> +#include <aws/core/monitoring/MonitoringManager.h> +#include <aws/core/Core_EXPORTS.h> + +namespace Aws +{ + static const char* DEFAULT_LOG_PREFIX = "aws_sdk_"; + + /** + * SDK wide options for logging + */ + struct LoggingOptions + { + LoggingOptions() : logLevel(Aws::Utils::Logging::LogLevel::Off), defaultLogPrefix(DEFAULT_LOG_PREFIX) + { } + + /** + * Defaults to Off, if this is set to something else, then logging will be turned on and logLevel will be passed to the logger + */ + Aws::Utils::Logging::LogLevel logLevel; + + /** + * Defaults to aws_sdk_. This will only be used if the default logger is used. + */ + const char* defaultLogPrefix; + + /** + * Defaults to empty, if logLevel has been set and this field is empty, then the default log interface will be used. + * otherwise, we will call this closure to create a logger + */ + std::function<std::shared_ptr<Aws::Utils::Logging::LogSystemInterface>()> logger_create_fn; + }; + + /** + * SDK wide options for memory management + */ + struct MemoryManagementOptions + { + MemoryManagementOptions() : memoryManager(nullptr) + { } + + /** + * Defaults to nullptr. If custom memory management is being used and this hasn't been set then the default memory + * manager will be used. If this has been set and custom memory management has been turned on, then this will be installed + * at startup time. + */ + Aws::Utils::Memory::MemorySystemInterface* memoryManager; + }; + + /** + * SDK wide options for http + */ + struct HttpOptions + { + HttpOptions() : initAndCleanupCurl(true), installSigPipeHandler(false) + { } + + /** + * Defaults to empty, if this is set, then the result of your closure will be installed and used instead of the system defaults + */ + std::function<std::shared_ptr<Aws::Http::HttpClientFactory>()> httpClientFactory_create_fn; + /** + * libCurl infects everything with its global state. If it is being used then we automatically initialize and clean it up. + * If this is a problem for you, set this to false. If you manually initialize libcurl please add the option CURL_GLOBAL_ALL to your init call. + */ + bool initAndCleanupCurl; + /** + * Installs a global SIGPIPE handler that logs the error and prevents it from terminating the current process. + * This can be used on operating systems on which CURL is being used. In some situations CURL cannot avoid + * triggering a SIGPIPE. + * For more information see: https://curl.haxx.se/libcurl/c/CURLOPT_NOSIGNAL.html + * NOTE: CURLOPT_NOSIGNAL is already being set. + */ + bool installSigPipeHandler; + }; + + /** + * SDK wide options for crypto + */ + struct CryptoOptions + { + CryptoOptions() : initAndCleanupOpenSSL(true) + { } + + /** + * If set, this closure will be used to create and install the factory. + */ + std::function<std::shared_ptr<Aws::Utils::Crypto::HashFactory>()> md5Factory_create_fn; + /** + * If set, this closure will be used to create and install the factory. + */ + std::function<std::shared_ptr<Aws::Utils::Crypto::HashFactory>()> sha256Factory_create_fn; + /** + * If set, this closure will be used to create and install the factory. + */ + std::function<std::shared_ptr<Aws::Utils::Crypto::HMACFactory>()> sha256HMACFactory_create_fn; + /** + * If set, this closure will be used to create and install the factory. + */ + std::function<std::shared_ptr<Aws::Utils::Crypto::SymmetricCipherFactory>()> aes_CBCFactory_create_fn; + /** + * If set, this closure will be used to create and install the factory. + */ + std::function<std::shared_ptr<Aws::Utils::Crypto::SymmetricCipherFactory>()> aes_CTRFactory_create_fn; + /** + * If set, this closure will be used to create and install the factory. + */ + std::function<std::shared_ptr<Aws::Utils::Crypto::SymmetricCipherFactory>()> aes_GCMFactory_create_fn; + /** + * If set, this closure will be used to create and install the factory. + */ + std::function<std::shared_ptr<Aws::Utils::Crypto::SymmetricCipherFactory>()> aes_KeyWrapFactory_create_fn; + /** + * If set, this closure will be used to create and install the factory. + */ + std::function<std::shared_ptr<Aws::Utils::Crypto::SecureRandomFactory>()> secureRandomFactory_create_fn; + /** + * OpenSSL infects everything with its global state. If it is being used then we automatically initialize and clean it up. + * If this is a problem for you, set this to false. Be aware that if you don't use our init and cleanup and you are using + * crypto functionality, you are responsible for installing thread locking, and loading strings and error messages. + */ + bool initAndCleanupOpenSSL; + }; + + /** + * MonitoringOptions is used to set up monitoring functionalities globally and(or) for users to customize monitoring listeners. + */ + struct MonitoringOptions + { + /** + * These factory functions will be used to try to create customized monitoring listener factories, then be used to create monitoring listener instances. + * Based on functions and factory's implementation, it may fail to create an instance. + * If a function failed to create factory or a created factory failed to create an instance, SDK just ignore it. + * By default, SDK will try to create a default Client Side Monitoring Listener. + */ + std::vector<Aws::Monitoring::MonitoringFactoryCreateFunction> customizedMonitoringFactory_create_fn; + }; + + + /** + * You may notice that instead of taking pointers directly to your factories, we take a closure. This is because + * if you have installed custom memory management, the allocation for your factories needs to happen after + * the memory system has been initialized and shutdown needs to happen prior to the memory management being shutdown. + * + * Common Recipes: + * + * Just use defaults: + * + * SDKOptions options; + * Aws::InitAPI(options); + * ..... + * Aws::ShutdownAPI(options); + * + * Turn logging on using the default logger: + * + * SDKOptions options; + * options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Info; + * Aws::InitAPI(options); + * ..... + * Aws::ShutdownAPI(options); + * + * Install custom memory manager: + * + * MyMemoryManager memoryManager; + * + * SDKOptions options; + * options.memoryManagementOptions.memoryManager = &memoryManager; + * Aws::InitAPI(options); + * ..... + * Aws::ShutdownAPI(options); + * + * Override default http client factory + * + * SDKOptions options; + * options.httpOptions.httpClientFactory_create_fn = [](){ return Aws::MakeShared<MyCustomHttpClientFactory>("ALLOC_TAG", arg1); }; + * Aws::InitAPI(options); + * ..... + * Aws::ShutdownAPI(options); + */ + struct SDKOptions + { + /** + * SDK wide options for logging + */ + LoggingOptions loggingOptions; + /** + * SDK wide options for memory management + */ + MemoryManagementOptions memoryManagementOptions; + /** + * SDK wide options for http + */ + HttpOptions httpOptions; + /** + * SDK wide options for crypto + */ + CryptoOptions cryptoOptions; + + /** + * Options used to set up customized monitoring implementations + * Put your monitoring factory in a closure (a create factory function) and put all closures in a vector. + * Basic usage can be found in aws-cpp-sdk-core-tests/monitoring/MonitoringTest.cpp + */ + MonitoringOptions monitoringOptions; + }; + + /* + * Initialize SDK wide state for the SDK. This method must be called before doing anything else with this library. + * + * Common Recipes: + * + * Just use defaults: + * + * SDKOptions options; + * Aws::InitAPI(options); + * ..... + * Aws::ShutdownAPI(options); + * + * Turn logging on using the default logger: + * + * SDKOptions options; + * options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Info; + * Aws::InitAPI(options); + * ..... + * Aws::ShutdownAPI(options); + * + * Install custom memory manager: + * + * MyMemoryManager memoryManager; + * + * SDKOptions options; + * options.memoryManagementOptions.memoryManager = &memoryManager; + * Aws::InitAPI(options); + * ..... + * Aws::ShutdownAPI(options); + * + * Override default http client factory + * + * SDKOptions options; + * options.httpOptions.httpClientFactory_create_fn = [](){ return Aws::MakeShared<MyCustomHttpClientFactory>("ALLOC_TAG", arg1); }; + * Aws::InitAPI(options); + * ..... + * Aws::ShutdownAPI(options); + */ + AWS_CORE_API void InitAPI(const SDKOptions& options); + + /** + * Shutdown SDK wide state for the SDK. This method must be called when you are finished using the SDK. + * Do not call any other SDK methods after calling ShutdownAPI. + */ + AWS_CORE_API void ShutdownAPI(const SDKOptions& options); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/Core_EXPORTS.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/Core_EXPORTS.h new file mode 100644 index 0000000000..12e9dfc9be --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/Core_EXPORTS.h @@ -0,0 +1,103 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/SDKConfig.h> + +#if defined (USE_WINDOWS_DLL_SEMANTICS) || defined (_WIN32) + #ifdef _MSC_VER + #pragma warning(disable : 4251) + #endif // _MSC_VER + + #ifdef USE_IMPORT_EXPORT + #ifdef AWS_CORE_EXPORTS + #define AWS_CORE_API __declspec(dllexport) + #else // AWS_CORE_EXPORTS + #define AWS_CORE_API __declspec(dllimport) + #endif // AWS_CORE_EXPORTS + #else // USE_IMPORT_EXPORT + #define AWS_CORE_API + #endif // USE_IMPORT_EXPORT +#else // defined (USE_WINDOWS_DLL_SEMANTICS) || defined (_WIN32) + #define AWS_CORE_API +#endif // defined (USE_WINDOWS_DLL_SEMANTICS) || defined (_WIN32) + +#ifdef _MSC_VER + #define AWS_SUPPRESS_WARNING_PUSH(W) \ + __pragma(warning(push)) \ + __pragma(warning(disable:W)) + + #define AWS_SUPPRESS_WARNING_POP __pragma(warning(pop)) + + #define AWS_SUPPRESS_WARNING(W, ...) \ + AWS_SUPPRESS_WARNING_PUSH(W) \ + __VA_ARGS__; \ + AWS_SUPPRESS_WARNING_POP + + #define AWS_SUPPRESS_DEPRECATION(...) AWS_SUPPRESS_WARNING(4996, __VA_ARGS__) + +#elif defined (__clang__) + #define DO_PRAGMA(x) _Pragma(#x) + + #define AWS_SUPPRESS_WARNING_PUSH(W) \ + DO_PRAGMA(clang diagnostic push) \ + DO_PRAGMA(clang diagnostic ignored W) + + #define AWS_SUPPRESS_WARNING_POP DO_PRAGMA(clang diagnostic pop) + + #define AWS_SUPPRESS_WARNING(W, ...) \ + AWS_SUPPRESS_WARNING_PUSH(W) \ + __VA_ARGS__; \ + AWS_SUPPRESS_WARNING_POP + + #define AWS_SUPPRESS_DEPRECATION(...) AWS_SUPPRESS_WARNING("-Wdeprecated-declarations", __VA_ARGS__) + +#elif defined (__GNUC__) + #define DO_PRAGMA(x) _Pragma(#x) + + #define AWS_SUPPRESS_WARNING_PUSH(W) \ + DO_PRAGMA(GCC diagnostic push) \ + DO_PRAGMA(GCC diagnostic ignored W) + + #define AWS_SUPPRESS_WARNING_POP DO_PRAGMA(GCC diagnostic pop) + /** + * WRAP_() is a useless macro to get around GCC quirks related to expanding macros which includes _Pragma + * see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=715271 + * and https://stackoverflow.com/questions/49698645/how-to-use-pragma-operator-in-macro + */ + #define WRAP_(W, ...) \ + W \ + __VA_ARGS__ \ + AWS_SUPPRESS_WARNING_POP + + #define AWS_SUPPRESS_WARNING(W, ...) WRAP_(AWS_SUPPRESS_WARNING_PUSH(W), __VA_ARGS__) + + #define AWS_SUPPRESS_DEPRECATION(...) AWS_SUPPRESS_WARNING("-Wdeprecated-declarations", __VA_ARGS__) + +#else + #define AWS_SUPPRESS_WARNING(W, ...) __VAR_ARGS__ + #define AWS_SUPPRESS_WARNING_PUSH(W) + #define AWS_SUPPRESS_WARNING_POP + #define AWS_SUPPRESS_DEPRECATION(...) __VA_ARGS__ +#endif + +// Due to MSVC can't recognize base class deprecated function in derived class. +// We need AWS_DISABLE_DEPRECATION to make AWS_DEPRECATED useless only on MSVC +// Update: When deprecating a function/components, we won't remove the existing tests +// immediately, so we need AWS_DISABLE_DEPRECATION as well. +#if defined(AWS_DISABLE_DEPRECATION) + #define AWS_DEPRECATED(msg) +#elif defined (__cplusplus) && __cplusplus > 201103L // standard attributes are available since C++14 + #define AWS_DEPRECATED(msg) [[deprecated(msg)]] +#else + #ifdef _MSC_VER + #define AWS_DEPRECATED(msg) __declspec(deprecated(msg)) + #elif defined (__clang__) || defined (__GNUC__) + #define AWS_DEPRECATED(msg) __attribute__((deprecated(msg))) + #else + #define AWS_DEPRECATED(msg) + #endif +#endif diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/Globals.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/Globals.h new file mode 100644 index 0000000000..cebe4891b7 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/Globals.h @@ -0,0 +1,35 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +namespace Aws +{ + namespace Utils + { + class EnumParseOverflowContainer; + } + /** + * This is used to handle the Enum round tripping problem + * for when a service updates their enumerations, but the user does not + * have an up to date client. This container will be initialized during Aws::InitAPI + * and will be cleaned on Aws::ShutdownAPI. + */ + AWS_CORE_API Utils::EnumParseOverflowContainer* GetEnumOverflowContainer(); + + /** + * Initializes a global overflow container to a new instance. + * This should only be called once from within Aws::InitAPI + */ + void InitializeEnumOverflowContainer(); + + /** + * Destroys the global overflow container instance. + * This should only be called once from within Aws::ShutdownAPI + */ + void CleanupEnumOverflowContainer(); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/NoResult.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/NoResult.h new file mode 100644 index 0000000000..c4f233cbb9 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/NoResult.h @@ -0,0 +1,32 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +namespace Aws +{ +namespace Utils +{ +namespace Xml +{ + class XmlDocument; +} +namespace Json +{ + class JsonValue; +} +} // namespace Utils + +class AWS_CORE_API NoResult +{ +public: + NoResult() {}; + NoResult(const Aws::AmazonWebServiceResult<Aws::Utils::Xml::XmlDocument>&) {}; + NoResult(const Aws::AmazonWebServiceResult<Aws::Utils::Json::JsonValue>&) {}; +}; + +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/Region.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/Region.h new file mode 100644 index 0000000000..a728c829ed --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/Region.h @@ -0,0 +1,53 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ + /** + * AWS Regions + */ + namespace Region + { + // AWS_GLOBAL is a pseudo region that can be used to tell SDK to use the service global endpoint if there is any. + // You can specify this region to corresponding environment variable, config file item and in your code. + // For services without global region, the request will be directed to us-east-1 + static const char AWS_GLOBAL[] = "aws-global"; + static const char US_EAST_1[] = "us-east-1"; + static const char US_EAST_2[] = "us-east-2"; + static const char US_WEST_1[] = "us-west-1"; + static const char US_WEST_2[] = "us-west-2"; + static const char AF_SOUTH_1[] = "af-south-1"; + static const char EU_WEST_1[] = "eu-west-1"; + static const char EU_WEST_2[] = "eu-west-2"; + static const char EU_WEST_3[] = "eu-west-3"; + static const char EU_CENTRAL_1[] = "eu-central-1"; + static const char EU_NORTH_1[] = "eu-north-1"; + static const char AP_EAST_1[] = "ap-east-1"; + static const char AP_SOUTH_1[] = "ap-south-1"; + static const char AP_SOUTHEAST_1[] = "ap-southeast-1"; + static const char AP_SOUTHEAST_2[] = "ap-southeast-2"; + static const char AP_NORTHEAST_1[] = "ap-northeast-1"; + static const char AP_NORTHEAST_2[] = "ap-northeast-2"; + static const char AP_NORTHEAST_3[] = "ap-northeast-3"; + static const char SA_EAST_1[] = "sa-east-1"; + static const char CA_CENTRAL_1[] = "ca-central-1"; + static const char CN_NORTH_1[] = "cn-north-1"; + static const char CN_NORTHWEST_1[] = "cn-northwest-1"; + static const char ME_SOUTH_1[] = "me-south-1"; + static const char US_GOV_WEST_1[] = "us-gov-west-1"; + static const char US_GOV_EAST_1[] = "us-gov-east-1"; + + // If a pseudo region, for example, aws-global or us-east-1-fips is provided, it should be converted to the region name used for signing. + Aws::String AWS_CORE_API ComputeSignerRegion(const Aws::String& region); + } + +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/SDKConfig.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/SDKConfig.h new file mode 100644 index 0000000000..9561d20253 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/SDKConfig.h @@ -0,0 +1,7 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +/* #undef USE_AWS_MEMORY_MANAGEMENT */ + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/Version.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/Version.h new file mode 100644 index 0000000000..71215ec6bd --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/Version.h @@ -0,0 +1,19 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ +namespace Version +{ + AWS_CORE_API const char* GetVersionString(); + AWS_CORE_API unsigned GetVersionMajor(); + AWS_CORE_API unsigned GetVersionMinor(); + AWS_CORE_API unsigned GetVersionPatch(); + AWS_CORE_API const char* GetCompilerVersionString(); +} //namespace Version +} //namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/VersionConfig.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/VersionConfig.h new file mode 100644 index 0000000000..9304d56ee7 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/VersionConfig.h @@ -0,0 +1,6 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#define AWS_SDK_VERSION_STRING "1.8.113" diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/AWSAuthSigner.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/AWSAuthSigner.h new file mode 100644 index 0000000000..8061ee1e25 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/AWSAuthSigner.h @@ -0,0 +1,425 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/Region.h> +#include <aws/core/utils/memory/AWSMemory.h> +#include <aws/core/utils/memory/stl/AWSSet.h> +#include <aws/core/utils/DateTime.h> +#include <aws/core/utils/Array.h> +#include <aws/core/utils/threading/ReaderWriterLock.h> +#include <aws/core/utils/crypto/Sha256.h> +#include <aws/core/utils/crypto/Sha256HMAC.h> + +#include <memory> +#include <atomic> +#include <chrono> + +namespace Aws +{ + namespace Http + { + class HttpClientFactory; + class HttpRequest; + } // namespace Http + + namespace Utils + { + namespace Event + { + class Message; + } + } // namespace Utils + + namespace Auth + { + class AWSCredentials; + class AWSCredentialsProvider; + AWS_CORE_API extern const char SIGV4_SIGNER[]; + AWS_CORE_API extern const char EVENTSTREAM_SIGV4_SIGNER[]; + AWS_CORE_API extern const char SIGNATURE[]; + AWS_CORE_API extern const char NULL_SIGNER[]; + } // namespace Auth + + namespace Client + { + struct ClientConfiguration; + + /** + * Auth Signer interface. Takes a generic AWS request and applies crypto tamper resistent signatures on the request. + */ + class AWS_CORE_API AWSAuthSigner + { + public: + AWSAuthSigner() : m_clockSkew() { m_clockSkew.store(std::chrono::milliseconds(0L)); } + virtual ~AWSAuthSigner() = default; + + /** + * Signs the request itself (usually by adding a signature header) based on info in the request and uri. + */ + virtual bool SignRequest(Aws::Http::HttpRequest& request) const = 0; + + /** + * Signs the request itself (usually by adding a signature header) based on info in the request and uri. + * If signBody is false and https is being used then the body of the payload will not be signed. + * The default virtual function, just calls SignRequest. + */ + virtual bool SignRequest(Aws::Http::HttpRequest& request, bool signBody) const + { + AWS_UNREFERENCED_PARAM(signBody); + return SignRequest(request); + } + + /** + * Signs the request itself (usually by adding a signature header) based on info in the request and uri. + * If signBody is false and https is being used then the body of the payload will not be signed. + * The default virtual function, just calls SignRequest. + * Using m_region by default if parameter region is nullptr. + */ + virtual bool SignRequest(Aws::Http::HttpRequest& request, const char* region, bool signBody) const + { + AWS_UNREFERENCED_PARAM(signBody); + AWS_UNREFERENCED_PARAM(region); + return SignRequest(request); + } + + /** + * Signs the request itself (usually by adding a signature header) based on info in the request and uri. + * If signBody is false and https is being used then the body of the payload will not be signed. + * The default virtual function, just calls SignRequest. + * Using m_region by default if parameter region is nullptr. + * Using m_serviceName by default if parameter serviceName is nullptr. + */ + virtual bool SignRequest(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, bool signBody) const + { + AWS_UNREFERENCED_PARAM(signBody); + AWS_UNREFERENCED_PARAM(region); + AWS_UNREFERENCED_PARAM(serviceName); + return SignRequest(request); + } + + /** + * Signs a single event message in an event stream. + * The input message buffer is copied and signed. The message's input buffer will be deallocated and a new + * buffer will be assigned. The new buffer encodes the original message with its headers as the payload of + * the new message. The signature of the original message will be added as a header to the new message. + * + * A Hex encoded signature of the previous event (or of the HTTP request headers in case of the first event) + * is provided as the 'priorSignature' parameter. 'priorSignature' will contain the value of the new + * signature after this call returns successfully. + * + * The function returns true if the message is successfully signed. + */ + virtual bool SignEventMessage(Aws::Utils::Event::Message&, Aws::String& /* priorSignature */) const { return false; } + + /** + * Takes a request and signs the URI based on the HttpMethod, URI and other info from the request. + * The URI can then be used in a normal HTTP call until expiration. + */ + virtual bool PresignRequest(Aws::Http::HttpRequest& request, long long expirationInSeconds) const = 0; + + /** + * Generates a signed Uri using the injected signer. for the supplied uri and http method and region. expirationInSeconds defaults + * to 0 which is the default 7 days. + * Using m_region by default if parameter region is nullptr. + */ + virtual bool PresignRequest(Aws::Http::HttpRequest& request, const char* region, long long expirationInSeconds = 0) const = 0; + + /** + * Generates a signed Uri using the injected signer. for the supplied uri and http method, region, and service name. expirationInSeconds defaults + * to 0 which is the default 7 days. + * Using m_region by default if parameter region is nullptr. + * Using m_serviceName by default if parameter serviceName is nullptr. + */ + virtual bool PresignRequest(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, long long expirationInSeconds = 0) const = 0; + + /** + * Return the signer's name + */ + virtual const char* GetName() const = 0; + + /** + * This handles detection of clock skew between clients and the server and adjusts the clock so that the next request will not + * fail on the timestamp check. + */ + virtual void SetClockSkew(const std::chrono::milliseconds& clockSkew) { m_clockSkew = clockSkew; } + + /** + * Gets the timestamp being used by the signer. This may include a clock skew if a clock skew has been detected. + */ + virtual Aws::Utils::DateTime GetSigningTimestamp() const { return Aws::Utils::DateTime::Now() + GetClockSkewOffset(); } + + protected: + virtual std::chrono::milliseconds GetClockSkewOffset() const { return m_clockSkew.load(); } + + std::atomic<std::chrono::milliseconds> m_clockSkew; + }; + + /** + * AWS Auth v4 Signer implementation of the AWSAuthSigner interface. More information on AWS Auth v4 Can be found here: + * http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html + */ + class AWS_CORE_API AWSAuthV4Signer : public AWSAuthSigner + { + + public: + /** + * Even though different payload signing polices, HTTP will force payload signing to be on. + */ + enum class PayloadSigningPolicy + { + /** + * Sign the request based on the value returned by AmazonWebServiceRequest::SignBody() + */ + RequestDependent, + /** + * Always sign the body of the request. + */ + Always, + /** + * Never sign the body of the request + */ + Never + }; + /** + * credentialsProvider, source of AWS Credentials to sign requests with + * serviceName, canonical service name to sign with + * region, region string to use in signature + * signPayloads, if Always, the payload will have a sha256 computed on the body of the request. If this is set + * to Never, the sha256 will not be computed on the body. This is only useful for Amazon S3 over Https. If + * Https is not used then this flag will be ignored. If set to RequestDependent, compute or not is based on + * the value from AmazonWebServiceRequest::SignBody() + */ + AWSAuthV4Signer(const std::shared_ptr<Auth::AWSCredentialsProvider>& credentialsProvider, + const char* serviceName, const Aws::String& region, PayloadSigningPolicy signingPolicy = PayloadSigningPolicy::RequestDependent, + bool urlEscapePath = true); + + virtual ~AWSAuthV4Signer(); + + /** + * AWSAuthV4signer's implementation of virtual function from base class + * Return Auth Signer's name, here the value is specified in Aws::Auth::DEFAULT_AUTHV4_SIGNER. + */ + const char* GetName() const override { return Aws::Auth::SIGV4_SIGNER; } + + /** + * Signs the request itself based on info in the request and uri. + * Uses AWS Auth V4 signing method with SHA256 HMAC algorithm. + */ + bool SignRequest(Aws::Http::HttpRequest& request) const override + { + return SignRequest(request, m_region.c_str(), m_serviceName.c_str(), true/*signBody*/); + } + + /** + * Signs the request itself based on info in the request and uri. + * Uses AWS Auth V4 signing method with SHA256 HMAC algorithm. If signBody is false + * and https is being used then the body of the payload will not be signed. + */ + bool SignRequest(Aws::Http::HttpRequest& request, bool signBody) const override + { + return SignRequest(request, m_region.c_str(), m_serviceName.c_str(), signBody); + } + + /** + * Uses AWS Auth V4 signing method with SHA256 HMAC algorithm. If signBody is false + * and https is being used then the body of the payload will not be signed. + * Using m_region by default if parameter region is nullptr. + */ + bool SignRequest(Aws::Http::HttpRequest& request, const char* region, bool signBody) const override + { + return SignRequest(request, region, m_serviceName.c_str(), signBody); + } + + /** + * Uses AWS Auth V4 signing method with SHA256 HMAC algorithm. If signBody is false + * and https is being used then the body of the payload will not be signed. + * Using m_region by default if parameter region is nullptr. + */ + bool SignRequest(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, bool signBody) const override; + + /** + * Takes a request and signs the URI based on the HttpMethod, URI and other info from the request. + * the region the signer was initialized with will be used for the signature. + * The URI can then be used in a normal HTTP call until expiration. + * Uses AWS Auth V4 signing method with SHA256 HMAC algorithm. + * expirationInSeconds defaults to 0 which provides a URI good for 7 days. + */ + bool PresignRequest(Aws::Http::HttpRequest& request, long long expirationInSeconds = 0) const override; + + /** + * Takes a request and signs the URI based on the HttpMethod, URI and other info from the request. + * The URI can then be used in a normal HTTP call until expiration. + * Uses AWS Auth V4 signing method with SHA256 HMAC algorithm. + * expirationInSeconds defaults to 0 which provides a URI good for 7 days. + * Using m_region by default if parameter region is nullptr. + */ + bool PresignRequest(Aws::Http::HttpRequest& request, const char* region, long long expirationInSeconds = 0) const override; + + /** + * Takes a request and signs the URI based on the HttpMethod, URI and other info from the request. + * The URI can then be used in a normal HTTP call until expiration. + * Uses AWS Auth V4 signing method with SHA256 HMAC algorithm. + * expirationInSeconds defaults to 0 which provides a URI good for 7 days. + * Using m_region by default if parameter region is nullptr. + * Using m_serviceName by default if parameter serviceName is nullptr. + */ + bool PresignRequest(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, long long expirationInSeconds = 0) const override; + + Aws::String GetServiceName() const { return m_serviceName; } + Aws::String GetRegion() const { return m_region; } + Aws::String GenerateSignature(const Aws::Auth::AWSCredentials& credentials, + const Aws::String& stringToSign, const Aws::String& simpleDate) const; + bool ShouldSignHeader(const Aws::String& header) const; + + protected: + bool m_includeSha256HashHeader; + + private: + + Aws::String GenerateSignature(const Aws::Auth::AWSCredentials& credentials, + const Aws::String& stringToSign, const Aws::String& simpleDate, const Aws::String& region, + const Aws::String& serviceName) const; + + Aws::String GenerateSignature(const Aws::String& stringToSign, const Aws::Utils::ByteBuffer& key) const; + bool ServiceRequireUnsignedPayload(const Aws::String& serviceName) const; + Aws::String ComputePayloadHash(Aws::Http::HttpRequest&) const; + Aws::String GenerateStringToSign(const Aws::String& dateValue, const Aws::String& simpleDate, + const Aws::String& canonicalRequestHash, const Aws::String& region, + const Aws::String& serviceName) const; + Aws::Utils::ByteBuffer ComputeHash(const Aws::String& secretKey, const Aws::String& simpleDate) const; + Aws::Utils::ByteBuffer ComputeHash(const Aws::String& secretKey, + const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const; + + + std::shared_ptr<Auth::AWSCredentialsProvider> m_credentialsProvider; + const Aws::String m_serviceName; + const Aws::String m_region; + Aws::UniquePtr<Aws::Utils::Crypto::Sha256> m_hash; + Aws::UniquePtr<Aws::Utils::Crypto::Sha256HMAC> m_HMAC; + + Aws::Set<Aws::String> m_unsignedHeaders; + + //these next four fields are ONLY for caching purposes and do not change + //the logical state of the signer. They are marked mutable so the + //interface can remain const. + mutable Aws::Utils::ByteBuffer m_partialSignature; + mutable Aws::String m_currentDateStr; + mutable Aws::String m_currentSecretKey; + mutable Utils::Threading::ReaderWriterLock m_partialSignatureLock; + PayloadSigningPolicy m_payloadSigningPolicy; + bool m_urlEscapePath; + }; + + class AWS_CORE_API AWSAuthEventStreamV4Signer : public AWSAuthSigner + { + public: + AWSAuthEventStreamV4Signer(const std::shared_ptr<Auth::AWSCredentialsProvider>& credentialsProvider, + const char* serviceName, const Aws::String& region); + + const char* GetName() const override { return Aws::Auth::EVENTSTREAM_SIGV4_SIGNER; } + + bool SignEventMessage(Aws::Utils::Event::Message&, Aws::String& priorSignature) const override; + + bool SignRequest(Aws::Http::HttpRequest& request) const override + { + return SignRequest(request, m_region.c_str(), m_serviceName.c_str(), true); + } + + bool SignRequest(Aws::Http::HttpRequest& request, bool signBody) const override + { + return SignRequest(request, m_region.c_str(), m_serviceName.c_str(), signBody); + } + + bool SignRequest(Aws::Http::HttpRequest& request, const char* region, bool signBody) const override + { + return SignRequest(request, region, m_serviceName.c_str(), signBody); + } + + bool SignRequest(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, bool signBody) const override; + + /** + * Do nothing + */ + bool PresignRequest(Aws::Http::HttpRequest&, long long) const override { return false; } + + /** + * Do nothing + */ + bool PresignRequest(Aws::Http::HttpRequest&, const char*, long long) const override { return false; } + + /** + * Do nothing + */ + bool PresignRequest(Aws::Http::HttpRequest&, const char*, const char*, long long) const override { return false; } + + bool ShouldSignHeader(const Aws::String& header) const; + private: + Utils::ByteBuffer GenerateSignature(const Aws::Auth::AWSCredentials& credentials, + const Aws::String& stringToSign, const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const; + Utils::ByteBuffer GenerateSignature(const Aws::String& stringToSign, const Aws::Utils::ByteBuffer& key) const; + Aws::String GenerateStringToSign(const Aws::String& dateValue, const Aws::String& simpleDate, + const Aws::String& canonicalRequestHash, const Aws::String& region, + const Aws::String& serviceName) const; + Aws::Utils::ByteBuffer ComputeHash(const Aws::String& secretKey, const Aws::String& simpleDate) const; + Aws::Utils::ByteBuffer ComputeHash(const Aws::String& secretKey, + const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const; + const Aws::String m_serviceName; + const Aws::String m_region; + mutable Aws::Utils::Crypto::Sha256 m_hash; + mutable Aws::Utils::Crypto::Sha256HMAC m_HMAC; + mutable Utils::Threading::ReaderWriterLock m_derivedKeyLock; + mutable Aws::Utils::ByteBuffer m_derivedKey; + mutable Aws::String m_currentDateStr; + mutable Aws::String m_currentSecretKey; + Aws::Vector<Aws::String> m_unsignedHeaders; + std::shared_ptr<Auth::AWSCredentialsProvider> m_credentialsProvider; + }; + + + /** + * A no-op implementation of the AWSAuthSigner interface + */ + class AWS_CORE_API AWSNullSigner : public AWSAuthSigner + { + public: + /** + * AWSNullSigner's implementation of virtual function from base class + * Here the returned value is specified in Aws::Auth::NULL_SIGNER. + */ + const char* GetName() const override { return Aws::Auth::NULL_SIGNER; } + + /** + * Do nothing + */ + bool SignRequest(Aws::Http::HttpRequest&) const override { return true; } + + /** + * Do nothing + */ + bool SignEventMessage(Aws::Utils::Event::Message&, Aws::String& /* priorSignature */) const override { return true; } + + /** + * Do nothing + */ + bool PresignRequest(Aws::Http::HttpRequest&, long long) const override { return false; } + + /** + * Do nothing + */ + bool PresignRequest(Aws::Http::HttpRequest&, const char*, long long) const override { return false; } + + /** + * Do nothing + */ + bool PresignRequest(Aws::Http::HttpRequest&, const char*, const char*, long long) const override { return false; } + }; + + } // namespace Client +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/AWSAuthSignerProvider.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/AWSAuthSignerProvider.h new file mode 100644 index 0000000000..305c58cd9d --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/AWSAuthSignerProvider.h @@ -0,0 +1,53 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/memory/stl/AWSVector.h> +#include <memory> + + +namespace Aws +{ + namespace Client + { + class AWSAuthSigner; + } + namespace Auth + { + class AWSCredentialsProvider; + + class AWS_CORE_API AWSAuthSignerProvider + { + public: + virtual std::shared_ptr<Aws::Client::AWSAuthSigner> GetSigner(const Aws::String& signerName) const = 0; + virtual void AddSigner(std::shared_ptr<Aws::Client::AWSAuthSigner>& signer) = 0; + virtual ~AWSAuthSignerProvider() = default; + }; + + class AWS_CORE_API DefaultAuthSignerProvider : public AWSAuthSignerProvider + { + public: + /** + * Creates a Signature-V4 signer provider that supports the different implementations of Signature-V4 + * used for standard and event-stream requests. + * + * @param credentialsProvider A provider to retrieve the access/secret key used to derive the signing + * @param serviceName The canonical name of the AWS service to be used in the signature + * @param region The AWS region in which the requests will be made. + */ + DefaultAuthSignerProvider(const std::shared_ptr<AWSCredentialsProvider>& credentialsProvider, + const Aws::String& serviceName, const Aws::String& region); + explicit DefaultAuthSignerProvider(const std::shared_ptr<Aws::Client::AWSAuthSigner>& signer); + void AddSigner(std::shared_ptr<Aws::Client::AWSAuthSigner>& signer) override; + std::shared_ptr<Aws::Client::AWSAuthSigner> GetSigner(const Aws::String& signerName) const override; + private: + Aws::Vector<std::shared_ptr<Aws::Client::AWSAuthSigner>> m_signers; + }; + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/AWSCredentials.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/AWSCredentials.h new file mode 100644 index 0000000000..1c14b955fc --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/AWSCredentials.h @@ -0,0 +1,176 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + #pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/DateTime.h> +namespace Aws +{ + namespace Auth + { + /** + * Simple data object around aws credentials + */ + class AWS_CORE_API AWSCredentials + { + public: + /** + * Initializes an empty credentials set. + * Empty credentials are not expired by default. + * Credentials expire only if an expiration date is explicitly set on them. + */ + AWSCredentials() : m_expiration((std::chrono::time_point<std::chrono::system_clock>::max)()) + { + } + + /** + * Initializes object with accessKeyId, secretKey. + * SessionToken defaults to empty string. + * Expiration date is set to "never expire". + */ + AWSCredentials(const Aws::String& accessKeyId, const Aws::String& secretKey) : + m_accessKeyId(accessKeyId), m_secretKey(secretKey), m_expiration((std::chrono::time_point<std::chrono::system_clock>::max)()) + { + } + + /** + * Initializes object with accessKeyId, secretKey, and sessionToken. + * Expiration date is set to "never expire". + */ + AWSCredentials(const Aws::String& accessKeyId, const Aws::String& secretKey, const Aws::String& sessionToken) : + m_accessKeyId(accessKeyId), m_secretKey(secretKey), m_sessionToken(sessionToken), m_expiration((std::chrono::time_point<std::chrono::system_clock>::max)()) + { + } + + /** + * Initializes object with accessKeyId, secretKey, sessionToken and expiration date. + */ + AWSCredentials(const Aws::String& accessKeyId, const Aws::String& secretKey, const Aws::String& sessionToken, Aws::Utils::DateTime expiration) : + m_accessKeyId(accessKeyId), m_secretKey(secretKey), m_sessionToken(sessionToken), m_expiration(expiration) + { + } + + bool operator == (const AWSCredentials& other) const + { + return m_accessKeyId == other.m_accessKeyId + && m_secretKey == other.m_secretKey + && m_sessionToken == other.m_sessionToken + && m_expiration == other.m_expiration; + } + + bool operator != (const AWSCredentials& other) const + { + return !(other == *this); + } + + /** + * If credentials haven't been initialized or been initialized to emtpy values. + * Expiration date does not affect the result of this function. + */ + inline bool IsEmpty() const { return m_accessKeyId.empty() && m_secretKey.empty(); } + + inline bool IsExpired() const { return m_expiration <= Aws::Utils::DateTime::Now(); } + + inline bool IsExpiredOrEmpty() const { return IsEmpty() || IsExpired(); } + + /** + * Gets the underlying access key credential + */ + inline const Aws::String& GetAWSAccessKeyId() const + { + return m_accessKeyId; + } + + /** + * Gets the underlying secret key credential + */ + inline const Aws::String& GetAWSSecretKey() const + { + return m_secretKey; + } + + /** + * Gets the underlying session token + */ + inline const Aws::String& GetSessionToken() const + { + return m_sessionToken; + } + + /** + * Gets the expiration date of the credential + */ + inline Aws::Utils::DateTime GetExpiration() const + { + return m_expiration; + } + + /** + * Sets the underlying access key credential. Copies from parameter accessKeyId. + */ + inline void SetAWSAccessKeyId(const Aws::String& accessKeyId) + { + m_accessKeyId = accessKeyId; + } + + /** + * Sets the underlying secret key credential. Copies from parameter secretKey + */ + inline void SetAWSSecretKey(const Aws::String& secretKey) + { + m_secretKey = secretKey; + } + + /** + * Sets the underlying session token. Copies from parameter sessionToken + */ + inline void SetSessionToken(const Aws::String& sessionToken) + { + m_sessionToken = sessionToken; + } + + + /** + * Sets the underlying access key credential. Copies from parameter accessKeyId. + */ + inline void SetAWSAccessKeyId(const char* accessKeyId) + { + m_accessKeyId = accessKeyId; + } + + /** + * Sets the underlying secret key credential. Copies from parameter secretKey + */ + inline void SetAWSSecretKey(const char* secretKey) + { + m_secretKey = secretKey; + } + + /** + * Sets the underlying secret key credential. Copies from parameter secretKey + */ + inline void SetSessionToken(const char* sessionToken) + { + m_sessionToken = sessionToken; + } + + /** + * Sets the expiration date of the credential + */ + inline void SetExpiration(Aws::Utils::DateTime expiration) + { + m_expiration = expiration; + } + + private: + Aws::String m_accessKeyId; + Aws::String m_secretKey; + Aws::String m_sessionToken; + Aws::Utils::DateTime m_expiration; + }; + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/AWSCredentialsProvider.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/AWSCredentialsProvider.h new file mode 100644 index 0000000000..a3a46964e8 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/AWSCredentialsProvider.h @@ -0,0 +1,316 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/UnreferencedParam.h> +#include <aws/core/utils/DateTime.h> +#include <aws/core/utils/memory/stl/AWSMap.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/threading/ReaderWriterLock.h> +#include <aws/core/internal/AWSHttpResourceClient.h> +#include <aws/core/auth/AWSCredentials.h> +#include <aws/core/config/AWSProfileConfigLoader.h> +#include <aws/core/client/RetryStrategy.h> +#include <memory> + +namespace Aws +{ + namespace Auth + { + constexpr int REFRESH_THRESHOLD = 1000 * 60 * 5; + + /** + * Returns the full path of the config file. + */ + AWS_CORE_API Aws::String GetConfigProfileFilename(); //defaults to "config" + + /** + * Returns the default profile name. + * The value is the first non-empty value of the following: + * 1. AWS_PROFILE environment variable + * 2. AWS_DEFAULT_PROFILE environment variable + * 3. The literal name "default" + */ + AWS_CORE_API Aws::String GetConfigProfileName(); //defaults to "default" + + /* + * Fetches credentials by executing the process in the parameter + */ + AWS_CORE_API AWSCredentials GetCredentialsFromProcess(const Aws::String& process); + + /** + * Abstract class for retrieving AWS credentials. Create a derived class from this to allow + * various methods of storing and retrieving credentials. Examples would be cognito-identity, some encrypted store etc... + */ + class AWS_CORE_API AWSCredentialsProvider + { + public: + /** + * Initializes provider. Sets last Loaded time count to 0, forcing a refresh on the + * first call to GetAWSCredentials. + */ + AWSCredentialsProvider() : m_lastLoadedMs(0) + { + } + + virtual ~AWSCredentialsProvider() = default; + + /** + * The core of the credential provider interface. Override this method to control how credentials are retrieved. + */ + virtual AWSCredentials GetAWSCredentials() = 0; + + protected: + /** + * The default implementation keeps up with the cache times and lets you know if it's time to refresh your internal caching + * to aid your implementation of GetAWSCredentials. + */ + virtual bool IsTimeToRefresh(long reloadFrequency); + virtual void Reload(); + mutable Aws::Utils::Threading::ReaderWriterLock m_reloadLock; + private: + long long m_lastLoadedMs; + }; + + /** + * Simply a provider that always returns empty credentials. This is useful for a client that needs to make unsigned + * calls. + */ + class AWS_CORE_API AnonymousAWSCredentialsProvider : public AWSCredentialsProvider + { + public: + /** + * Returns empty credentials object. + */ + inline AWSCredentials GetAWSCredentials() override { return AWSCredentials(); } + }; + + /** + * A simple string provider. It takes the AccessKeyId and the SecretKey as constructor args and + * provides them through the interface. This is the default class for AWSClients that take string + * arguments for credentials. + */ + class AWS_CORE_API SimpleAWSCredentialsProvider : public AWSCredentialsProvider + { + public: + /** + * Initializes object from awsAccessKeyId, awsSecretAccessKey, and sessionToken parameters. sessionToken parameter is defaulted to empty. + */ + inline SimpleAWSCredentialsProvider(const Aws::String& awsAccessKeyId, const Aws::String& awsSecretAccessKey, const Aws::String& sessionToken = "") + : m_credentials(awsAccessKeyId, awsSecretAccessKey, sessionToken) + { } + + /** + * Initializes object from credentials object. everything is copied. + */ + inline SimpleAWSCredentialsProvider(const AWSCredentials& credentials) + : m_credentials(credentials) + { } + + /** + * Returns the credentials this object was initialized with as an AWSCredentials object. + */ + inline AWSCredentials GetAWSCredentials() override + { + return m_credentials; + } + + private: + AWSCredentials m_credentials; + }; + + /** + * Reads AWS credentials from the Environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN if they exist. If they + * are not found, empty credentials are returned. + */ + class AWS_CORE_API EnvironmentAWSCredentialsProvider : public AWSCredentialsProvider + { + public: + /** + * Reads AWS credentials from the Environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN if they exist. If they + * are not found, empty credentials are returned. Credentials are not cached. + */ + AWSCredentials GetAWSCredentials() override; + }; + + /** + * Reads credentials profile from the default Profile Config File. Refreshes at set interval for credential rotation. + * Looks for environment variables AWS_SHARED_CREDENTIALS_FILE and AWS_PROFILE. If they aren't found, then it defaults + * to the default profile in ~/.aws/credentials. + * Optionally a user can specify the profile and it will override the environment variable + * and defaults. To alter the file this pulls from, then the user should alter the AWS_SHARED_CREDENTIALS_FILE variable. + */ + class AWS_CORE_API ProfileConfigFileAWSCredentialsProvider : public AWSCredentialsProvider + { + public: + + /** + * Initializes with refreshRateMs as the frequency at which the file is reparsed in milliseconds. Defaults to 5 minutes. + */ + ProfileConfigFileAWSCredentialsProvider(long refreshRateMs = REFRESH_THRESHOLD); + + /** + * Initializes with a profile override and + * refreshRateMs as the frequency at which the file is reparsed in milliseconds. Defaults to 5 minutes. + */ + ProfileConfigFileAWSCredentialsProvider(const char* profile, long refreshRateMs = REFRESH_THRESHOLD); + + /** + * Retrieves the credentials if found, otherwise returns empty credential set. + */ + AWSCredentials GetAWSCredentials() override; + + /** + * Returns the fullpath of the calculated credentials profile file + */ + static Aws::String GetCredentialsProfileFilename(); + + /** + * Returns the directory storing the profile file. + */ + static Aws::String GetProfileDirectory(); + + protected: + void Reload() override; + private: + + /** + * Checks to see if the refresh interval has expired and reparses the file if it has. + */ + void RefreshIfExpired(); + + Aws::String m_profileToUse; + Aws::Config::AWSConfigFileProfileConfigLoader m_credentialsFileLoader; + long m_loadFrequencyMs; + }; + + /** + * Credentials provider implementation that loads credentials from the Amazon + * EC2 Instance Metadata Service. + */ + class AWS_CORE_API InstanceProfileCredentialsProvider : public AWSCredentialsProvider + { + public: + /** + * Initializes the provider to refresh credentials form the EC2 instance metadata service every 5 minutes. + * Constructs an EC2MetadataClient using the default http stack (most likely what you want). + */ + InstanceProfileCredentialsProvider(long refreshRateMs = REFRESH_THRESHOLD); + + /** + * Initializes the provider to refresh credentials form the EC2 instance metadata service every 5 minutes, + * uses a supplied EC2MetadataClient. + */ + InstanceProfileCredentialsProvider(const std::shared_ptr<Aws::Config::EC2InstanceProfileConfigLoader>&, long refreshRateMs = REFRESH_THRESHOLD); + + /** + * Retrieves the credentials if found, otherwise returns empty credential set. + */ + AWSCredentials GetAWSCredentials() override; + + protected: + void Reload() override; + + private: + void RefreshIfExpired(); + + std::shared_ptr<Aws::Config::AWSProfileConfigLoader> m_ec2MetadataConfigLoader; + long m_loadFrequencyMs; + }; + + /** + * ECS credentials provider implementation that loads credentials from the Amazon + * ECS metadata service or an arbitrary endpoint. + */ + class AWS_CORE_API TaskRoleCredentialsProvider : public AWSCredentialsProvider + { + public: + /** + * Initializes the provider to retrieve credentials from the ECS metadata service every 5 minutes, + * or before it expires. + * @param resourcePath A path appended to the metadata service endpoint. + * @param refreshRateMs The number of milliseconds after which the credentials will be fetched again. + */ + TaskRoleCredentialsProvider(const char* resourcePath, long refreshRateMs = REFRESH_THRESHOLD); + + /** + * Initializes the provider to retrieve credentials from a provided endpoint every 5 minutes or before it + * expires. + * @param endpoint The full URI to resolve to get credentials. + * @param token An optional authorization token passed to the URI via the 'Authorization' HTTP header. + * @param refreshRateMs The number of milliseconds after which the credentials will be fetched again. + */ + TaskRoleCredentialsProvider(const char* endpoint, const char* token, long refreshRateMs = REFRESH_THRESHOLD); + + /** + * Initializes the provider to retrieve credentials using the provided client. + * @param client The ECSCredentialsClient instance to use when retrieving credentials. + * @param refreshRateMs The number of milliseconds after which the credentials will be fetched again. + */ + TaskRoleCredentialsProvider(const std::shared_ptr<Aws::Internal::ECSCredentialsClient>& client, + long refreshRateMs = REFRESH_THRESHOLD); + /** + * Retrieves the credentials if found, otherwise returns empty credential set. + */ + AWSCredentials GetAWSCredentials() override; + + protected: + void Reload() override; + private: + bool ExpiresSoon() const; + void RefreshIfExpired(); + + private: + std::shared_ptr<Aws::Internal::ECSCredentialsClient> m_ecsCredentialsClient; + long m_loadFrequencyMs; + Aws::Auth::AWSCredentials m_credentials; + }; + + /** + * Process credentials provider that loads credentials by running another command (or program) configured in config file + * The configuration format is as following: + * credential_process = command_path <arguments_list> + * Each time the credentials needs to be refreshed, this command will be executed with configured arguments. + * The default profile name to look up this configuration is "default", same as normal aws credentials configuration and other configurations. + * The expected valid output of the command is a Json doc output to stdout: + * {"Version": 1, "AccessKeyId": "AccessKey123", "SecretAccessKey": "SecretKey321", "SessionToken": "Token123", "Expiration": "1970-01-01T00:00:01Z"} + * The Version key specifies the version of the JSON payload and must be set to 1 for now (as an integer type). + * If the Version key is bumped to 2, SDKs would support both versions of the returned payload. + * Value of Expiration field should be an valid ISO8601 formatted date string as above example. + * The expected error message of the command is a string to output to stderr. + */ + class AWS_CORE_API ProcessCredentialsProvider : public AWSCredentialsProvider + { + public: + /** + * Initializes the provider by checking default profile + */ + ProcessCredentialsProvider(); + + /** + * Initializes the provider by checking specified profile + * @param profile which profile in config file to use. + */ + ProcessCredentialsProvider(const Aws::String& profile); + + /** + * Retrieves the credentials if found, otherwise returns empty credential set. + */ + AWSCredentials GetAWSCredentials() override; + + protected: + void Reload() override; + private: + void RefreshIfExpired(); + + private: + Aws::String m_profileToUse; + Aws::Auth::AWSCredentials m_credentials; + }; + } // namespace Auth +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/AWSCredentialsProviderChain.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/AWSCredentialsProviderChain.h new file mode 100644 index 0000000000..dae8cf5a42 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/AWSCredentialsProviderChain.h @@ -0,0 +1,68 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSVector.h> +#include <aws/core/auth/AWSCredentialsProvider.h> +#include <memory> + +namespace Aws +{ + namespace Auth + { + /** + * Abstract class for providing chains of credentials providers. When a credentials provider in the chain returns empty credentials, + * We go on to the next provider until we have either exhausted the installed providers in the chain or something returns non-empty credentials. + */ + class AWS_CORE_API AWSCredentialsProviderChain : public AWSCredentialsProvider + { + public: + virtual ~AWSCredentialsProviderChain() = default; + + /** + * When a credentials provider in the chain returns empty credentials, + * We go on to the next provider until we have either exhausted the installed providers in the chain or something returns non-empty credentials. + */ + virtual AWSCredentials GetAWSCredentials(); + + /** + * Gets all providers stored in this chain. + */ + const Aws::Vector<std::shared_ptr<AWSCredentialsProvider>>& GetProviders() { return m_providerChain; } + + protected: + /** + * This class is only allowed to be initialized by subclasses. + */ + AWSCredentialsProviderChain() = default; + + /** + * Adds a provider to the back of the chain. + */ + void AddProvider(const std::shared_ptr<AWSCredentialsProvider>& provider) { m_providerChain.push_back(provider); } + + + private: + Aws::Vector<std::shared_ptr<AWSCredentialsProvider> > m_providerChain; + }; + + /** + * Creates an AWSCredentialsProviderChain which uses in order EnvironmentAWSCredentialsProvider, ProfileConfigFileAWSCredentialsProvider, + * and InstanceProfileCredentialsProvider. + */ + class AWS_CORE_API DefaultAWSCredentialsProviderChain : public AWSCredentialsProviderChain + { + public: + /** + * Initializes the provider chain with EnvironmentAWSCredentialsProvider, ProfileConfigFileAWSCredentialsProvider, + * and InstanceProfileCredentialsProvider in that order. + */ + DefaultAWSCredentialsProviderChain(); + }; + + } // namespace Auth +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/STSCredentialsProvider.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/STSCredentialsProvider.h new file mode 100644 index 0000000000..92d997c7ca --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/auth/STSCredentialsProvider.h @@ -0,0 +1,51 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/DateTime.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/internal/AWSHttpResourceClient.h> +#include <aws/core/auth/AWSCredentialsProvider.h> +#include <memory> + +namespace Aws +{ + namespace Auth + { + /** + * To support retrieving credentials of STS AssumeRole with web identity. + * Note that STS accepts request with protocol of queryxml. Calling GetAWSCredentials() will trigger (if expired) + * a query request using AWSHttpResourceClient under the hood. + */ + class AWS_CORE_API STSAssumeRoleWebIdentityCredentialsProvider : public AWSCredentialsProvider + { + public: + STSAssumeRoleWebIdentityCredentialsProvider(); + + /** + * Retrieves the credentials if found, otherwise returns empty credential set. + */ + AWSCredentials GetAWSCredentials() override; + + protected: + void Reload() override; + + private: + void RefreshIfExpired(); + Aws::String CalculateQueryString() const; + + Aws::UniquePtr<Aws::Internal::STSCredentialsClient> m_client; + Aws::Auth::AWSCredentials m_credentials; + Aws::String m_roleArn; + Aws::String m_tokenFile; + Aws::String m_sessionName; + Aws::String m_token; + bool m_initialized; + }; + } // namespace Auth +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/AWSClient.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/AWSClient.h new file mode 100644 index 0000000000..186206a66e --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/AWSClient.h @@ -0,0 +1,463 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/client/CoreErrors.h> +#include <aws/core/http/HttpTypes.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/AmazonWebServiceResult.h> +#include <aws/core/utils/crypto/Hash.h> +#include <aws/core/auth/AWSAuthSignerProvider.h> +#include <memory> +#include <atomic> + +struct aws_array_list; + +namespace Aws +{ + namespace Utils + { + template<typename R, typename E> + class Outcome; + + namespace Xml + { + class XmlDocument; + } // namespace Xml + + namespace Json + { + class JsonValue; + } // namespace Json + + namespace RateLimits + { + class RateLimiterInterface; + } // namespace RateLimits + + namespace Crypto + { + class MD5; + } // namespace Crypto + } // namespace Utils + + namespace Http + { + class HttpClient; + + class HttpClientFactory; + + class HttpRequest; + + class HttpResponse; + + class URI; + } // namespace Http + + namespace Auth + { + AWS_CORE_API extern const char SIGV4_SIGNER[]; + AWS_CORE_API extern const char NULL_SIGNER[]; + } + + class AmazonWebServiceRequest; + + namespace Client + { + template<typename ERROR_TYPE> + class AWSError; + class AWSErrorMarshaller; + class AWSRestfulJsonErrorMarshaller; + class AWSAuthSigner; + struct ClientConfiguration; + class RetryStrategy; + + typedef Utils::Outcome<std::shared_ptr<Aws::Http::HttpResponse>, AWSError<CoreErrors>> HttpResponseOutcome; + typedef Utils::Outcome<AmazonWebServiceResult<Utils::Stream::ResponseStream>, AWSError<CoreErrors>> StreamOutcome; + + /** + * Abstract AWS Client. Contains most of the functionality necessary to build an http request, get it signed, and send it accross the wire. + */ + class AWS_CORE_API AWSClient + { + public: + /** + * configuration will be used for http client settings, retry strategy, throttles, and signing information. + * supplied signer will be used for all requests, aws sdk clients will use default AuthV4Signer. + * errorMarshaller tells the client how to convert error payloads into AWSError objects. + */ + AWSClient(const Aws::Client::ClientConfiguration& configuration, + const std::shared_ptr<Aws::Client::AWSAuthSigner>& signer, + const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller); + + /** + * Configuration will be used for http client settings, retry strategy, throttles, and signing information. + * Pass a signer provider to determine the proper signer for a given request; AWS services will use + * SigV4 signer. errorMarshaller tells the client how to convert error payloads into AWSError objects. + */ + AWSClient(const Aws::Client::ClientConfiguration& configuration, + const std::shared_ptr<Aws::Auth::AWSAuthSignerProvider>& signerProvider, + const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller); + + virtual ~AWSClient() { }; + + /** + * Generates a signed Uri using the injected signer. for the supplied uri and http method. expirationInSeconds defaults + * to 0 which is the default 7 days. The implication of this function is using auth signer v4 to sign it. + */ + Aws::String GeneratePresignedUrl(Aws::Http::URI& uri, Aws::Http::HttpMethod method, long long expirationInSeconds = 0); + + /** + * Generates a signed Uri using the injected signer. for the supplied uri, http method and customized headers. expirationInSeconds defaults + * to 0 which is the default 7 days. The implication of this function is using auth signer v4 to sign it. + */ + Aws::String GeneratePresignedUrl(Aws::Http::URI& uri, Aws::Http::HttpMethod method, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds = 0); + + /** + * Generates a signed Uri using the injected signer. for the supplied uri and http method and region. expirationInSeconds defaults + * to 0 which is the default 7 days. + */ + Aws::String GeneratePresignedUrl(Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, long long expirationInSeconds = 0) const; + + /** + * Generates a signed Uri using the injected signer. for the supplied uri, http method and customized headers. expirationInSeconds defaults + * to 0 which is the default 7 days. + */ + Aws::String GeneratePresignedUrl(Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds = 0); + + /** + * Generates a signed Uri using the injected signer. for the supplied uri and http method, region, and service name. expirationInSeconds defaults + * to 0 which is the default 7 days. + */ + Aws::String GeneratePresignedUrl(Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, long long expirationInSeconds = 0) const; + + /** + * Generates a signed Uri using the injected signer. for the supplied uri, http method and customized headers. expirationInSeconds defaults + * to 0 which is the default 7 days. + */ + Aws::String GeneratePresignedUrl(Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds = 0); + + Aws::String GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, Aws::Http::URI& uri, Aws::Http::HttpMethod method, + const Aws::Http::QueryStringParameterCollection& extraParams = Aws::Http::QueryStringParameterCollection(), long long expirationInSeconds = 0) const; + + Aws::String GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, + const Aws::Http::QueryStringParameterCollection& extraParams = Aws::Http::QueryStringParameterCollection(), long long expirationInSeconds = 0) const; + + Aws::String GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, + const Aws::Http::QueryStringParameterCollection& extraParams = Aws::Http::QueryStringParameterCollection(), long long expirationInSeconds = 0) const; + + /** + * Stop all requests immediately. + * In flight requests will likely fail. + */ + void DisableRequestProcessing(); + + /** + * Enable/ReEnable requests. + */ + void EnableRequestProcessing(); + + inline virtual const char* GetServiceClientName() const { return m_serviceName.c_str(); } + /** + * service client name is part of userAgent. + * We need to update userAgent after setting this name if it's not pre-set by customer. + * Note: this API should only be called in your extended class constructors. + */ + virtual void SetServiceClientName(const Aws::String& name); + + protected: + /** + * Calls AttemptOneRequest until it either, succeeds, runs out of retries from the retry strategy, + * or encounters and error that is not retryable. + */ + HttpResponseOutcome AttemptExhaustively(const Aws::Http::URI& uri, + const Aws::AmazonWebServiceRequest& request, + Http::HttpMethod httpMethod, + const char* signerName, + const char* signerRegionOverride = nullptr, + const char* signerServiceNameOverride = nullptr) const; + + /** + * Calls AttemptOneRequest until it either, succeeds, runs out of retries from the retry strategy, + * or encounters and error that is not retryable. This method is for payloadless requests e.g. GET, DELETE, HEAD + * + * requestName is used for metrics and defaults to empty string, to avoid empty names in metrics provide a valid + * name. + */ + HttpResponseOutcome AttemptExhaustively(const Aws::Http::URI& uri, + Http::HttpMethod httpMethod, + const char* signerName, + const char* requestName = "", + const char* signerRegionOverride = nullptr, + const char* signerServiceNameOverride = nullptr) const; + + /** + * Build an Http Request from the AmazonWebServiceRequest object. Signs the request, sends it accross the wire + * then reports the http response. + */ + HttpResponseOutcome AttemptOneRequest(const std::shared_ptr<Http::HttpRequest>& httpRequest, + const Aws::AmazonWebServiceRequest& request, + const char* signerName, + const char* signerRegionOverride = nullptr, + const char* signerServiceNameOverride = nullptr) const; + + /** + * Signs an Http Request, sends it accross the wire + * then reports the http response. This method is for payloadless requests e.g. GET, DELETE, HEAD + * + * requestName is used for metrics and defaults to empty string, to avoid empty names in metrics provide a valid + * name. + */ + HttpResponseOutcome AttemptOneRequest(const std::shared_ptr<Http::HttpRequest>& httpRequest, + const char* signerName, + const char* requestName = "", + const char* signerRegionOverride = nullptr, + const char* signerServiceNameOverride = nullptr) const; + + /** + * This is used for structureless response payloads (file streams, binary data etc...). It calls AttemptExhaustively, but upon + * return transfers ownership of the underlying stream for the http response to the caller. + */ + StreamOutcome MakeRequestWithUnparsedResponse(const Aws::Http::URI& uri, + const Aws::AmazonWebServiceRequest& request, + Http::HttpMethod method = Http::HttpMethod::HTTP_POST, + const char* signerName = Aws::Auth::SIGV4_SIGNER, + const char* signerRegionOverride = nullptr, + const char* signerServiceNameOverride = nullptr) const; + + /** + * This is used for structureless response payloads (file streams, binary data etc...). It calls AttemptExhaustively, but upon + * return transfers ownership of the underlying stream for the http response to the caller. + * + * requestName is used for metrics and defaults to empty string, to avoid empty names in metrics provide a valid + * name. + */ + StreamOutcome MakeRequestWithUnparsedResponse(const Aws::Http::URI& uri, + Http::HttpMethod method = Http::HttpMethod::HTTP_POST, + const char* signerName = Aws::Auth::SIGV4_SIGNER, + const char* requestName = "", + const char* signerRegionOverride = nullptr, + const char* signerServiceNameOverride = nullptr) const; + + /** + * Abstract. Subclassing clients should override this to tell the client how to marshall error payloads + */ + virtual AWSError<CoreErrors> BuildAWSError(const std::shared_ptr<Aws::Http::HttpResponse>& response) const = 0; + + /** + * Transforms the AmazonWebServicesResult object into an HttpRequest. + */ + virtual void BuildHttpRequest(const Aws::AmazonWebServiceRequest& request, + const std::shared_ptr<Aws::Http::HttpRequest>& httpRequest) const; + + /** + * Gets the underlying ErrorMarshaller for subclasses to use. + */ + const std::shared_ptr<AWSErrorMarshaller>& GetErrorMarshaller() const + { + return m_errorMarshaller; + } + + /** + * Gets the corresponding signer from the signers map by name. + */ + Aws::Client::AWSAuthSigner* GetSignerByName(const char* name) const; + protected: + + /** + * Creates an HttpRequest instance with the given URI and sets the proper headers from the + * AmazonWebRequest, and finally signs that request with the given the signer. + * The similar member function BuildHttpRequest() does not sign the request. + * This member function is used internally only by clients that perform requests (input operations) using + * event-streams. + */ + std::shared_ptr<Aws::Http::HttpRequest> BuildAndSignHttpRequest(const Aws::Http::URI& uri, + const Aws::AmazonWebServiceRequest& request, + Http::HttpMethod method, const char* signerName) const; + + /** + * Performs the HTTP request via the HTTP client while enforcing rate limiters + */ + std::shared_ptr<Aws::Http::HttpResponse> MakeHttpRequest(std::shared_ptr<Aws::Http::HttpRequest>& request) const; + Aws::String m_region; + private: + /** + * Try to adjust signer's clock + * return true if signer's clock is adjusted, false otherwise. + */ + bool AdjustClockSkew(HttpResponseOutcome& outcome, const char* signerName) const; + void AddHeadersToRequest(const std::shared_ptr<Aws::Http::HttpRequest>& httpRequest, const Http::HeaderValueCollection& headerValues) const; + void AddContentBodyToRequest(const std::shared_ptr<Aws::Http::HttpRequest>& httpRequest, const std::shared_ptr<Aws::IOStream>& body, + bool needsContentMd5 = false, bool isChunked = false) const; + void AddCommonHeaders(Aws::Http::HttpRequest& httpRequest) const; + void InitializeGlobalStatics(); + std::shared_ptr<Aws::Http::HttpRequest> ConvertToRequestForPresigning(const Aws::AmazonWebServiceRequest& request, Aws::Http::URI& uri, + Aws::Http::HttpMethod method, const Aws::Http::QueryStringParameterCollection& extraParams) const; + + std::shared_ptr<Aws::Http::HttpClient> m_httpClient; + std::shared_ptr<Aws::Auth::AWSAuthSignerProvider> m_signerProvider; + std::shared_ptr<AWSErrorMarshaller> m_errorMarshaller; + std::shared_ptr<RetryStrategy> m_retryStrategy; + std::shared_ptr<Aws::Utils::RateLimits::RateLimiterInterface> m_writeRateLimiter; + std::shared_ptr<Aws::Utils::RateLimits::RateLimiterInterface> m_readRateLimiter; + Aws::String m_userAgent; + bool m_customizedUserAgent; + std::shared_ptr<Aws::Utils::Crypto::Hash> m_hash; + long m_requestTimeoutMs; + bool m_enableClockSkewAdjustment; + Aws::String m_serviceName; + }; + + typedef Utils::Outcome<AmazonWebServiceResult<Utils::Json::JsonValue>, AWSError<CoreErrors>> JsonOutcome; + AWS_CORE_API Aws::String GetAuthorizationHeader(const Aws::Http::HttpRequest& httpRequest); + + /** + * AWSClient that handles marshalling json response bodies. You would inherit from this class + * to create a client that uses Json as its payload format. + */ + class AWS_CORE_API AWSJsonClient : public AWSClient + { + public: + typedef AWSClient BASECLASS; + + /** + * Simply calls AWSClient constructor. + */ + AWSJsonClient(const Aws::Client::ClientConfiguration& configuration, + const std::shared_ptr<Aws::Client::AWSAuthSigner>& signer, + const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller); + + /** + * Simply calls AWSClient constructor. + */ + AWSJsonClient(const Aws::Client::ClientConfiguration& configuration, + const std::shared_ptr<Aws::Auth::AWSAuthSignerProvider>& signerProvider, + const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller); + + virtual ~AWSJsonClient() = default; + + protected: + /** + * Converts/Parses an http response into a meaningful AWSError object using the json message structure. + */ + virtual AWSError<CoreErrors> BuildAWSError(const std::shared_ptr<Aws::Http::HttpResponse>& response) const override; + + /** + * Returns a Json document or an error from the request. Does some marshalling json and raw streams, + * then just calls AttemptExhaustively. + * + * method defaults to POST + */ + JsonOutcome MakeRequest(const Aws::Http::URI& uri, + const Aws::AmazonWebServiceRequest& request, + Http::HttpMethod method = Http::HttpMethod::HTTP_POST, + const char* signerName = Aws::Auth::SIGV4_SIGNER, + const char* signerRegionOverride = nullptr, + const char* signerServiceNameOverride = nullptr) const; + + /** + * Returns a Json document or an error from the request. Does some marshalling json and raw streams, + * then just calls AttemptExhaustively. + * + * requestName is used for metrics and defaults to empty string, to avoid empty names in metrics provide a valid + * name. + * + * method defaults to POST + */ + JsonOutcome MakeRequest(const Aws::Http::URI& uri, + Http::HttpMethod method = Http::HttpMethod::HTTP_POST, + const char* signerName = Aws::Auth::SIGV4_SIGNER, + const char* requestName = "", + const char* signerRegionOverride = nullptr, + const char* signerServiceNameOverride = nullptr) const; + + JsonOutcome MakeEventStreamRequest(std::shared_ptr<Aws::Http::HttpRequest>& request) const; + }; + + typedef Utils::Outcome<AmazonWebServiceResult<Utils::Xml::XmlDocument>, AWSError<CoreErrors>> XmlOutcome; + + /** + * AWSClient that handles marshalling xml response bodies. You would inherit from this class + * to create a client that uses Xml as its payload format. + */ + class AWS_CORE_API AWSXMLClient : public AWSClient + { + public: + + typedef AWSClient BASECLASS; + + AWSXMLClient(const Aws::Client::ClientConfiguration& configuration, + const std::shared_ptr<Aws::Client::AWSAuthSigner>& signer, + const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller); + + AWSXMLClient(const Aws::Client::ClientConfiguration& configuration, + const std::shared_ptr<Aws::Auth::AWSAuthSignerProvider>& signerProvider, + const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller); + + virtual ~AWSXMLClient() = default; + + protected: + /** + * Converts/Parses an http response into a meaningful AWSError object. Using the XML message structure. + */ + virtual AWSError<CoreErrors> BuildAWSError(const std::shared_ptr<Aws::Http::HttpResponse>& response) const override; + + /** + * Returns an xml document or an error from the request. Does some marshalling xml and raw streams, + * then just calls AttemptExhaustively. + * + * method defaults to POST + */ + XmlOutcome MakeRequest(const Aws::Http::URI& uri, + const Aws::AmazonWebServiceRequest& request, + Http::HttpMethod method = Http::HttpMethod::HTTP_POST, + const char* signerName = Aws::Auth::SIGV4_SIGNER, + const char* signerRegionOverride = nullptr, + const char* signerServiceNameOverride = nullptr) const; + + + /** + * Returns an xml document or an error from the request. Does some marshalling xml and raw streams, + * then just calls AttemptExhaustively. + * + * requestName is used for metrics and defaults to empty string, to avoid empty names in metrics provide a valid + * name. + * + * method defaults to POST + */ + XmlOutcome MakeRequest(const Aws::Http::URI& uri, + Http::HttpMethod method = Http::HttpMethod::HTTP_POST, + const char* signerName = Aws::Auth::SIGV4_SIGNER, + const char* requestName = "", + const char* signerRegionOverride = nullptr, + const char* signerServiceNameOverride = nullptr) const; + + /** + * This is used for event stream response. + */ + XmlOutcome MakeRequestWithEventStream(const Aws::Http::URI& uri, + const Aws::AmazonWebServiceRequest& request, + Http::HttpMethod method = Http::HttpMethod::HTTP_POST, + const char* singerName = Aws::Auth::SIGV4_SIGNER, + const char* signerRegionOverride = nullptr, + const char* signerServiceNameOverride = nullptr) const; + + /** + * This is used for event stream response. + * requestName is used for metrics and defaults to empty string, to avoid empty names in metrics provide a valid + * name. + */ + XmlOutcome MakeRequestWithEventStream(const Aws::Http::URI& uri, + Http::HttpMethod method = Http::HttpMethod::HTTP_POST, + const char* signerName = Aws::Auth::SIGV4_SIGNER, + const char* requestName = "", + const char* signerRegionOverride = nullptr, + const char* signerServiceNameOverride = nullptr) const; + }; + + } // namespace Client +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/AWSError.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/AWSError.h new file mode 100644 index 0000000000..c88c1bdd5d --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/AWSError.h @@ -0,0 +1,220 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/http/HttpResponse.h> +#include <aws/core/utils/xml/XmlSerializer.h> +#include <aws/core/utils/json/JsonSerializer.h> +#include <aws/core/utils/StringUtils.h> + +namespace Aws +{ + namespace Client + { + enum class CoreErrors; + class XmlErrorMarshaller; + class JsonErrorMarshaller; + + enum class ErrorPayloadType + { + NOT_SET, + XML, + JSON + }; + + /** + * Container for Error enumerations with additional exception information. Name, message, retryable etc.... + */ + template<typename ERROR_TYPE> + class AWSError + { + // Allow ErrorMarshaller to set error payload. + friend class XmlErrorMarshaller; + friend class JsonErrorMarshaller; + template<typename T> friend class AWSError; + public: + /** + * Initializes AWSError object as empty with the error not being retryable. + */ + AWSError() : m_responseCode(Aws::Http::HttpResponseCode::REQUEST_NOT_MADE), m_isRetryable(false) {} + /** + * Initializes AWSError object with errorType, exceptionName, message, and retryable flag. + */ + AWSError(ERROR_TYPE errorType, Aws::String exceptionName, const Aws::String message, bool isRetryable) : + m_errorType(errorType), m_exceptionName(exceptionName), m_message(message), + m_responseCode(Aws::Http::HttpResponseCode::REQUEST_NOT_MADE), m_isRetryable(isRetryable), + m_errorPayloadType(ErrorPayloadType::NOT_SET) {} + /** + * Initializes AWSError object with errorType and retryable flag. ExceptionName and message are empty. + */ + AWSError(ERROR_TYPE errorType, bool isRetryable) : + m_errorType(errorType), m_responseCode(Aws::Http::HttpResponseCode::REQUEST_NOT_MADE), + m_isRetryable(isRetryable), m_errorPayloadType(ErrorPayloadType::NOT_SET) {} + + AWSError(AWSError&& rhs) = default; + AWSError(const AWSError& rhs) = default; + + template<typename OTHER_ERROR_TYPE> + AWSError(AWSError<OTHER_ERROR_TYPE>&& rhs) : + m_errorType(static_cast<ERROR_TYPE>(rhs.m_errorType)), m_exceptionName(std::move(rhs.m_exceptionName)), + m_message(std::move(rhs.m_message)), m_remoteHostIpAddress(std::move(rhs.m_remoteHostIpAddress)), + m_requestId(std::move(rhs.m_requestId)), m_responseHeaders(std::move(rhs.m_responseHeaders)), + m_responseCode(rhs.m_responseCode), m_isRetryable(rhs.m_isRetryable), m_errorPayloadType(rhs.m_errorPayloadType), + m_xmlPayload(std::move(rhs.m_xmlPayload)), m_jsonPayload(std::move(rhs.m_jsonPayload)) + {} + + template<typename OTHER_ERROR_TYPE> + AWSError(const AWSError<OTHER_ERROR_TYPE>& rhs) : + m_errorType(static_cast<ERROR_TYPE>(rhs.m_errorType)), m_exceptionName(rhs.m_exceptionName), + m_message(rhs.m_message), m_remoteHostIpAddress(rhs.m_remoteHostIpAddress), m_requestId(rhs.m_requestId), + m_responseHeaders(rhs.m_responseHeaders), m_responseCode(rhs.m_responseCode), + m_isRetryable(rhs.m_isRetryable), m_errorPayloadType(rhs.m_errorPayloadType), + m_xmlPayload(rhs.m_xmlPayload), m_jsonPayload(rhs.m_jsonPayload) + {} + + /** + * Copy assignment operator + */ + AWSError& operator=(const AWSError<ERROR_TYPE>&) = default; + + /** + * Move assignment operator + */ + AWSError& operator=(AWSError<ERROR_TYPE>&& other) = default; + + /** + * Gets underlying errorType. + */ + inline const ERROR_TYPE GetErrorType() const { return m_errorType; } + /** + * Gets the underlying ExceptionName. + */ + inline const Aws::String& GetExceptionName() const { return m_exceptionName; } + /** + *Sets the underlying ExceptionName. + */ + inline void SetExceptionName(const Aws::String& exceptionName) { m_exceptionName = exceptionName; } + /** + * Gets the error message. + */ + inline const Aws::String& GetMessage() const { return m_message; } + /** + * Sets the error message + */ + inline void SetMessage(const Aws::String& message) { m_message = message; } + /** + * Gets the resolved remote host IP address. + * This value is only available after DNS resolution and with CURL http client right now. + * Otherwise an empty string is returned. + */ + inline const Aws::String& GetRemoteHostIpAddress() const { return m_remoteHostIpAddress; } + /** + * Sets the resolved remote host IP address. + */ + inline void SetRemoteHostIpAddress(const Aws::String& remoteHostIpAddress) { m_remoteHostIpAddress = remoteHostIpAddress; } + /** + * Gets the request ID. + * This value is available after request is made and when services return it in response. + * Otherwise an empty string is returned. + */ + inline const Aws::String& GetRequestId() const { return m_requestId; } + /** + * Sets the request ID. + */ + inline void SetRequestId(const Aws::String& requestId) { m_requestId = requestId; } + /** + * Returns whether or not this error is eligible for retry. + */ + inline bool ShouldRetry() const { return m_isRetryable; } + /** + * Gets the response headers from the http response. + */ + inline const Aws::Http::HeaderValueCollection& GetResponseHeaders() const { return m_responseHeaders; } + /** + * Sets the response headers from the http response. + */ + inline void SetResponseHeaders(const Aws::Http::HeaderValueCollection& headers) { m_responseHeaders = headers; } + /** + * Tests whether or not a header exists. + */ + inline bool ResponseHeaderExists(const Aws::String& headerName) const { return m_responseHeaders.find(Aws::Utils::StringUtils::ToLower(headerName.c_str())) != m_responseHeaders.end(); } + /** + * Gets the response code from the http response + */ + inline Aws::Http::HttpResponseCode GetResponseCode() const { return m_responseCode; } + /** + * Sets the response code from the http response + */ + inline void SetResponseCode(Aws::Http::HttpResponseCode responseCode) { m_responseCode = responseCode; } + + protected: + inline ErrorPayloadType GetErrorPayloadType() { return m_errorPayloadType; } + inline void SetXmlPayload(const Aws::Utils::Xml::XmlDocument& xmlPayload) + { + m_errorPayloadType = ErrorPayloadType::XML; + m_xmlPayload = xmlPayload; + } + inline void SetXmlPayload(Aws::Utils::Xml::XmlDocument&& xmlPayload) + { + m_errorPayloadType = ErrorPayloadType::XML; + m_xmlPayload = std::move(xmlPayload); + } + inline const Aws::Utils::Xml::XmlDocument& GetXmlPayload() const + { + assert(m_errorPayloadType != ErrorPayloadType::JSON); + return m_xmlPayload; + } + inline void SetJsonPayload(const Aws::Utils::Json::JsonValue& jsonPayload) + { + m_errorPayloadType = ErrorPayloadType::JSON; + m_jsonPayload = jsonPayload; + } + inline void SetJsonPayload(Aws::Utils::Json::JsonValue&& jsonPayload) + { + m_errorPayloadType = ErrorPayloadType::JSON; + m_jsonPayload = std::move(jsonPayload); + } + inline const Aws::Utils::Json::JsonValue& GetJsonPayload() const + { + assert(m_errorPayloadType != ErrorPayloadType::XML); + return m_jsonPayload; + } + + ERROR_TYPE m_errorType; + Aws::String m_exceptionName; + Aws::String m_message; + Aws::String m_remoteHostIpAddress; + Aws::String m_requestId; + Aws::Http::HeaderValueCollection m_responseHeaders; + Aws::Http::HttpResponseCode m_responseCode; + bool m_isRetryable; + + ErrorPayloadType m_errorPayloadType; + Aws::Utils::Xml::XmlDocument m_xmlPayload; + Aws::Utils::Json::JsonValue m_jsonPayload; + }; + + template<typename T> + Aws::OStream& operator << (Aws::OStream& s, const AWSError<T>& e) + { + s << "HTTP response code: " << static_cast<int>(e.GetResponseCode()) << "\n" + << "Resolved remote host IP address: " << e.GetRemoteHostIpAddress() << "\n" + << "Request ID: " << e.GetRequestId() << "\n" + << "Exception name: " << e.GetExceptionName() << "\n" + << "Error message: " << e.GetMessage() << "\n" + << e.GetResponseHeaders().size() << " response headers:"; + + for (auto&& header : e.GetResponseHeaders()) + { + s << "\n" << header.first << " : " << header.second; + } + return s; + } + + } // namespace Client +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/AWSErrorMarshaller.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/AWSErrorMarshaller.h new file mode 100644 index 0000000000..628b9565fd --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/AWSErrorMarshaller.h @@ -0,0 +1,97 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ + namespace Http + { + class HttpResponse; + enum class HttpResponseCode; + } + + namespace Utils + { + namespace Xml + { + class XmlDocument; + } + namespace Json + { + class JsonValue; + } + } + + namespace Client + { + enum class CoreErrors; + + template<typename ERROR_TYPE> + class AWSError; + + /** + * Marshaller for core error types. + */ + class AWS_CORE_API AWSErrorMarshaller + { + public: + virtual ~AWSErrorMarshaller() {} + + /** + * Converts an exceptionName and message into an Error object, if it can be parsed. Otherwise, it returns + * and AWSError with CoreErrors::UNKNOWN as the error type. + */ + virtual AWSError<CoreErrors> Marshall(const Aws::Http::HttpResponse& response) const = 0; + /** + * Attempts to finds an error code by the exception name. Otherwise returns CoreErrors::UNKNOWN as the error type. + */ + virtual AWSError<CoreErrors> FindErrorByName(const char* exceptionName) const; + virtual AWSError<CoreErrors> FindErrorByHttpResponseCode(Aws::Http::HttpResponseCode code) const; + /** + * Attempts to extract region from error. + */ + virtual Aws::String ExtractRegion(const AWSError<CoreErrors>&) const { return {}; } + /** + * Attempts to extract endpoint from error. + */ + virtual Aws::String ExtractEndpoint(const AWSError<CoreErrors>&) const { return {}; } + protected: + AWSError<CoreErrors> Marshall(const Aws::String& exceptionName, const Aws::String& message) const; + }; + + class AWS_CORE_API JsonErrorMarshaller : public AWSErrorMarshaller + { + using AWSErrorMarshaller::Marshall; + public: + /** + * Converts an exceptionName and message into an Error object, if it can be parsed. Otherwise, it returns + * and AWSError with CoreErrors::UNKNOWN as the error type. + */ + AWSError<CoreErrors> Marshall(const Aws::Http::HttpResponse& response) const override; + + protected: + const Aws::Utils::Json::JsonValue& GetJsonPayloadFromError(const AWSError<CoreErrors>&) const; + }; + + class AWS_CORE_API XmlErrorMarshaller : public AWSErrorMarshaller + { + using AWSErrorMarshaller::Marshall; + public: + /** + * Converts an exceptionName and message into an Error object, if it can be parsed. Otherwise, it returns + * and AWSError with CoreErrors::UNKNOWN as the error type. + */ + AWSError<CoreErrors> Marshall(const Aws::Http::HttpResponse& response) const override; + + protected: + const Aws::Utils::Xml::XmlDocument& GetXmlPayloadFromError(const AWSError<CoreErrors>&) const; + }; + + } // namespace Client +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/AsyncCallerContext.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/AsyncCallerContext.h new file mode 100644 index 0000000000..6831791ffc --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/AsyncCallerContext.h @@ -0,0 +1,59 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ + namespace Client + { + /** + * Call-back context for all async client methods. This allows you to pass a context to your callbacks so that you can identify your requests. + * It is entirely intended that you override this class in-lieu of using a void* for the user context. The base class just gives you the ability to + * pass a uuid for your context. + */ + class AWS_CORE_API AsyncCallerContext + { + public: + /** + * Initializes object with generated UUID + */ + AsyncCallerContext(); + + /** + * Initializes object with UUID + */ + AsyncCallerContext(const Aws::String& uuid) : m_uuid(uuid) {} + + /** + * Initializes object with UUID + */ + AsyncCallerContext(const char* uuid) : m_uuid(uuid) {} + + virtual ~AsyncCallerContext() {} + + /** + * Gets underlying UUID + */ + inline const Aws::String& GetUUID() const { return m_uuid; } + + /** + * Sets underlying UUID + */ + inline void SetUUID(const Aws::String& value) { m_uuid = value; } + + /** + * Sets underlying UUID + */ + inline void SetUUID(const char* value) { m_uuid.assign(value); } + + private: + Aws::String m_uuid; + }; + } +} + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h new file mode 100644 index 0000000000..ba54baaa83 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h @@ -0,0 +1,255 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/http/Scheme.h> +#include <aws/core/Region.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/http/HttpTypes.h> +#include <memory> + +namespace Aws +{ + namespace Utils + { + namespace Threading + { + class Executor; + } // namespace Threading + + namespace RateLimits + { + class RateLimiterInterface; + } // namespace RateLimits + } // namespace Utils + namespace Client + { + class RetryStrategy; // forward declare + + /** + * Sets the behaviors of the underlying HTTP clients handling response with 30x status code. + * By default, HTTP clients will always redirect the 30x response automatically, except when + * specifying aws-global as the client region, then SDK will handle 30x response and redirect + * the request manually. + */ + enum class FollowRedirectsPolicy + { + DEFAULT, + ALWAYS, + NEVER + }; + + /** + * This mutable structure is used to configure any of the AWS clients. + * Default values can only be overwritten prior to passing to the client constructors. + */ + struct AWS_CORE_API ClientConfiguration + { + ClientConfiguration(); + + /** + * Create a configuration based on settings in the aws configuration file for the given profile name. + * The configuration file location can be set via the environment variable AWS_CONFIG_FILE + */ + ClientConfiguration(const char* profileName); + + /** + * User Agent string user for http calls. This is filled in for you in the constructor. Don't override this unless you have a really good reason. + */ + Aws::String userAgent; + /** + * Http scheme to use. E.g. Http or Https. Default HTTPS + */ + Aws::Http::Scheme scheme; + /** + * AWS Region to use in signing requests. Default US_EAST_1 + */ + Aws::String region; + /** + * Use dual stack endpoint in the endpoint calculation. It is your responsibility to verify that the service supports ipv6 in the region you select. + */ + bool useDualStack; + /** + * Max concurrent tcp connections for a single http client to use. Default 25. + */ + unsigned maxConnections; + /** + * This is currently only applicable for Curl to set the http request level timeout, including possible dns lookup time, connection establish time, ssl handshake time and actual data transmission time. + * the corresponding Curl option is CURLOPT_TIMEOUT_MS + * defaults to 0, no http request level timeout. + */ + long httpRequestTimeoutMs; + /** + * Socket read timeouts for HTTP clients on Windows. Default 3000 ms. This should be more than adequate for most services. However, if you are transfering large amounts of data + * or are worried about higher latencies, you should set to something that makes more sense for your use case. + * For Curl, it's the low speed time, which contains the time in number milliseconds that transfer speed should be below "lowSpeedLimit" for the library to consider it too slow and abort. + * Note that for Curl this config is converted to seconds by rounding down to the nearest whole second except when the value is greater than 0 and less than 1000. In this case it is set to one second. When it's 0, low speed limit check will be disabled. + * Note that for Windows when this config is 0, the behavior is not specified by Windows. + */ + long requestTimeoutMs; + /** + * Socket connect timeout. Default 1000 ms. Unless you are very far away from your the data center you are talking to. 1000ms is more than sufficient. + */ + long connectTimeoutMs; + /** + * Enable TCP keep-alive. Default true; + * No-op for WinHTTP, WinINet and IXMLHTTPRequest2 client. + */ + bool enableTcpKeepAlive; + /** + * Interval to send a keep-alive packet over the connection. Default 30 seconds. Minimum 15 seconds. + * WinHTTP & libcurl support this option. Note that for Curl, this value will be rounded to an integer with second granularity. + * No-op for WinINet and IXMLHTTPRequest2 client. + */ + unsigned long tcpKeepAliveIntervalMs; + /** + * Average transfer speed in bytes per second that the transfer should be below during the request timeout interval for it to be considered too slow and abort. + * Default 1 byte/second. Only for CURL client currently. + */ + unsigned long lowSpeedLimit; + /** + * Strategy to use in case of failed requests. Default is DefaultRetryStrategy (e.g. exponential backoff) + */ + std::shared_ptr<RetryStrategy> retryStrategy; + /** + * Override the http endpoint used to talk to a service. + */ + Aws::String endpointOverride; + /** + * If you have users going through a proxy, set the proxy scheme here. Default HTTP + */ + Aws::Http::Scheme proxyScheme; + /** + * If you have users going through a proxy, set the host here. + */ + Aws::String proxyHost; + /** + * If you have users going through a proxy, set the port here. + */ + unsigned proxyPort; + /** + * If you have users going through a proxy, set the username here. + */ + Aws::String proxyUserName; + /** + * If you have users going through a proxy, set the password here. + */ + Aws::String proxyPassword; + /** + * SSL Certificate file to use for connecting to an HTTPS proxy. + * Used to set CURLOPT_PROXY_SSLCERT in libcurl. Example: client.pem + */ + Aws::String proxySSLCertPath; + /** + * Type of proxy client SSL certificate. + * Used to set CURLOPT_PROXY_SSLCERTTYPE in libcurl. Example: PEM + */ + Aws::String proxySSLCertType; + /** + * Private key file to use for connecting to an HTTPS proxy. + * Used to set CURLOPT_PROXY_SSLKEY in libcurl. Example: key.pem + */ + Aws::String proxySSLKeyPath; + /** + * Type of private key file used to connect to an HTTPS proxy. + * Used to set CURLOPT_PROXY_SSLKEYTYPE in libcurl. Example: PEM + */ + Aws::String proxySSLKeyType; + /** + * Passphrase to the private key file used to connect to an HTTPS proxy. + * Used to set CURLOPT_PROXY_KEYPASSWD in libcurl. Example: password1 + */ + Aws::String proxySSLKeyPassword; + /** + * Threading Executor implementation. Default uses std::thread::detach() + */ + std::shared_ptr<Aws::Utils::Threading::Executor> executor; + /** + * If you need to test and want to get around TLS validation errors, do that here. + * you probably shouldn't use this flag in a production scenario. + */ + bool verifySSL; + /** + * If your Certificate Authority path is different from the default, you can tell + * clients that aren't using the default trust store where to find your CA trust store. + * If you are on windows or apple, you likely don't want this. + */ + Aws::String caPath; + /** + * Same as caPath, but useful if you have users going through a proxy. + * Used to set CURLOPT_PROXY_CAPATH in libcurl. + */ + Aws::String proxyCaPath; + /** + * If you certificate file is different from the default, you can tell clients that + * aren't using the default trust store where to find your ca file. + * If you are on windows or apple, you likely don't want this. + */ + Aws::String caFile; + /** + * Same as caFile, but useful if you have users going through a proxy. + * Used to set CURLOPT_PROXY_CAINFO in libcurl. + */ + Aws::String proxyCaFile; + /** + * Rate Limiter implementation for outgoing bandwidth. Default is wide-open. + */ + std::shared_ptr<Aws::Utils::RateLimits::RateLimiterInterface> writeRateLimiter; + /** + * Rate Limiter implementation for incoming bandwidth. Default is wide-open. + */ + std::shared_ptr<Aws::Utils::RateLimits::RateLimiterInterface> readRateLimiter; + /** + * Override the http implementation the default factory returns. + */ + Aws::Http::TransferLibType httpLibOverride; + /** + * Sets the behavior how http stack handles 30x redirect codes. + */ + FollowRedirectsPolicy followRedirects; + + /** + * Only works for Curl http client. + * Curl will by default add "Expect: 100-Continue" header in a Http request so as to avoid sending http + * payload to wire if server respond error immediately after receiving the header. + * Set this option to true will tell Curl to send http request header and body together. + * This can save one round-trip time and especially useful when the payload is small and network latency is more important. + * But be careful when Http request has large payload such S3 PutObject. You don't want to spend long time sending a large payload just getting a error response for server. + * The default value will be false. + */ + bool disableExpectHeader; + + /** + * If set to true clock skew will be adjusted after each http attempt, default to true. + */ + bool enableClockSkewAdjustment; + + /** + * Enable host prefix injection. + * For services whose endpoint is injectable. e.g. servicediscovery, you can modify the http host's prefix so as to add "data-" prefix for DiscoverInstances request. + * Default to true, enabled. You can disable it for testing purpose. + */ + bool enableHostPrefixInjection; + + /** + * Enable endpoint discovery + * For some services to dynamically set up their endpoints for different requests. + * Defaults to false, it's an opt-in feature. + * If disabled, regional or overriden endpoint will be used instead. + * If a request requires endpoint discovery but you disabled it. The request will never succeed. + */ + bool enableEndpointDiscovery; + + /** + * profileName in config file that will be used by this object to reslove more configurations. + */ + Aws::String profileName; + + }; + + } // namespace Client +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/CoreErrors.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/CoreErrors.h new file mode 100644 index 0000000000..52ebe51c82 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/CoreErrors.h @@ -0,0 +1,79 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include "aws/core/Core_EXPORTS.h" + +namespace Aws +{ + namespace Http + { + enum class HttpResponseCode; + } + namespace Client + { + template<typename ERROR_TYPE> + class AWSError; + + enum class CoreErrors + { + INCOMPLETE_SIGNATURE = 0, + INTERNAL_FAILURE = 1, + INVALID_ACTION = 2, + INVALID_CLIENT_TOKEN_ID = 3, + INVALID_PARAMETER_COMBINATION = 4, + INVALID_QUERY_PARAMETER = 5, + INVALID_PARAMETER_VALUE = 6, + MISSING_ACTION = 7, // SDK should never allow + MISSING_AUTHENTICATION_TOKEN = 8, // SDK should never allow + MISSING_PARAMETER = 9, // SDK should never allow + OPT_IN_REQUIRED = 10, + REQUEST_EXPIRED = 11, + SERVICE_UNAVAILABLE = 12, + THROTTLING = 13, + VALIDATION = 14, + ACCESS_DENIED = 15, + RESOURCE_NOT_FOUND = 16, // Shared with multiple services + UNRECOGNIZED_CLIENT = 17, // Most likely caused by an invalid access key or secret key + MALFORMED_QUERY_STRING = 18, // Where does this come from? (cognito identity uses it) + SLOW_DOWN = 19, + REQUEST_TIME_TOO_SKEWED = 20, + INVALID_SIGNATURE = 21, + SIGNATURE_DOES_NOT_MATCH = 22, + INVALID_ACCESS_KEY_ID = 23, + REQUEST_TIMEOUT = 24, + + NETWORK_CONNECTION = 99, // General failure to send message to service + + // These are needed for logical reasons + UNKNOWN = 100, // Unknown to the SDK + CLIENT_SIGNING_FAILURE = 101, // Client failed to sign the request + USER_CANCELLED = 102, // User cancelled the request + SERVICE_EXTENSION_START_RANGE = 128 + }; + + namespace CoreErrorsMapper + { + /** + * Finds a CoreErrors member if possible. Otherwise, returns UNKNOWN + */ + AWS_CORE_API AWSError<CoreErrors> GetErrorForName(const char* errorName); + + /** + * Build the mapping between predefined exception names and Aws CoreErrors using Aws::Map. + */ + AWS_CORE_API void InitCoreErrorsMapper(); + + /** + * Cleanup memory allocated for Aws::Map used by AWS CoreError Mapper. + */ + AWS_CORE_API void CleanupCoreErrorsMapper(); + /** + * Finds a CoreErrors member if possible by HTTP response code + */ + AWS_CORE_API AWSError<CoreErrors> GetErrorForHttpResponseCode(Aws::Http::HttpResponseCode code); + } // namespace CoreErrorsMapper + } // namespace Client +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/DefaultRetryStrategy.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/DefaultRetryStrategy.h new file mode 100644 index 0000000000..0357c5ed0c --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/DefaultRetryStrategy.h @@ -0,0 +1,36 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/client/RetryStrategy.h> + +namespace Aws +{ +namespace Client +{ + +class AWS_CORE_API DefaultRetryStrategy : public RetryStrategy +{ +public: + + DefaultRetryStrategy(long maxRetries = 10, long scaleFactor = 25) : + m_scaleFactor(scaleFactor), m_maxRetries(maxRetries) + {} + + bool ShouldRetry(const AWSError<CoreErrors>& error, long attemptedRetries) const override; + + long CalculateDelayBeforeNextRetry(const AWSError<CoreErrors>& error, long attemptedRetries) const override; + + virtual long GetMaxAttempts() const override { return m_maxRetries + 1; } + +protected: + long m_scaleFactor; + long m_maxRetries; +}; + +} // namespace Client +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/RetryStrategy.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/RetryStrategy.h new file mode 100644 index 0000000000..930eaa581d --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/RetryStrategy.h @@ -0,0 +1,121 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/threading/ReaderWriterLock.h> +#include <memory> + +namespace Aws +{ + namespace Http + { + class HttpResponse; + } + + namespace Utils + { + template<typename R, typename E> + class Outcome; + } + + namespace Client + { + enum class CoreErrors; + template<typename ERROR_TYPE> + class AWSError; + + typedef Utils::Outcome<std::shared_ptr<Aws::Http::HttpResponse>, AWSError<CoreErrors>> HttpResponseOutcome; + + /** + * Interface for defining a Retry Strategy. Override this class to provide your own custom retry behavior. + */ + class AWS_CORE_API RetryStrategy + { + public: + virtual ~RetryStrategy() = default; + /** + * Returns true if the error can be retried given the error and the number of times already tried. + */ + virtual bool ShouldRetry(const AWSError<CoreErrors>& error, long attemptedRetries) const = 0; + + /** + * Calculates the time in milliseconds the client should sleep before attempting another request based on the error and attemptedRetries count. + */ + virtual long CalculateDelayBeforeNextRetry(const AWSError<CoreErrors>& error, long attemptedRetries) const = 0; + + /** + * Gets max number of attempts allowed for an operation. + * Returns non positive value if not defined. + */ + virtual long GetMaxAttempts() const { return 0; } + + /** + * Retrives send tokens from the bucket. + */ + virtual void GetSendToken() {} + + /** + * Update status, like the information of retry quota when receiving a response. + */ + virtual void RequestBookkeeping(const HttpResponseOutcome& /* httpResponseOutcome */) {} + virtual void RequestBookkeeping(const HttpResponseOutcome& /* httpResponseOutcome */, const AWSError<CoreErrors>& /* lastError */) {} + }; + + /** + * The container for retry quotas. + * A failed request will acquire retry quotas to retry. + * And a successful request will release quotas back. + * If running out of retry quotas, then the client is not able to retry. + */ + class AWS_CORE_API RetryQuotaContainer + { + public: + virtual ~RetryQuotaContainer() = default; + virtual bool AcquireRetryQuota(int capacityAmount) = 0; + virtual bool AcquireRetryQuota(const AWSError<CoreErrors>& error) = 0; + virtual void ReleaseRetryQuota(int capacityAmount) = 0; + virtual void ReleaseRetryQuota(const AWSError<CoreErrors>& lastError) = 0; + virtual int GetRetryQuota() const = 0; + }; + + class AWS_CORE_API DefaultRetryQuotaContainer : public RetryQuotaContainer + { + public: + DefaultRetryQuotaContainer(); + virtual ~DefaultRetryQuotaContainer() = default; + virtual bool AcquireRetryQuota(int capacityAmount) override; + virtual bool AcquireRetryQuota(const AWSError<CoreErrors>& error) override; + virtual void ReleaseRetryQuota(int capacityAmount) override; + virtual void ReleaseRetryQuota(const AWSError<CoreErrors>& lastError) override; + virtual int GetRetryQuota() const override { return m_retryQuota; } + + protected: + mutable Aws::Utils::Threading::ReaderWriterLock m_retryQuotaLock; + int m_retryQuota; + }; + + class AWS_CORE_API StandardRetryStrategy : public RetryStrategy + { + public: + StandardRetryStrategy(long maxAttempts = 3); + StandardRetryStrategy(std::shared_ptr<RetryQuotaContainer> retryQuotaContainer, long maxAttempts = 3); + + virtual void RequestBookkeeping(const HttpResponseOutcome& httpResponseOutcome) override; + virtual void RequestBookkeeping(const HttpResponseOutcome& httpResponseOutcome, const AWSError<CoreErrors>& lastError) override; + + virtual bool ShouldRetry(const AWSError<CoreErrors>& error, long attemptedRetries) const override; + + virtual long CalculateDelayBeforeNextRetry(const AWSError<CoreErrors>& error, long attemptedRetries) const override; + + virtual long GetMaxAttempts() const override { return m_maxAttempts; } + + protected: + std::shared_ptr<RetryQuotaContainer> m_retryQuotaContainer; + long m_maxAttempts; + }; + } // namespace Client +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/SpecifiedRetryableErrorsRetryStrategy.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/SpecifiedRetryableErrorsRetryStrategy.h new file mode 100644 index 0000000000..09cfc95d8f --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/client/SpecifiedRetryableErrorsRetryStrategy.h @@ -0,0 +1,34 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/client/DefaultRetryStrategy.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/memory/stl/AWSVector.h> +namespace Aws +{ +namespace Client +{ + +/** + * @brief This retry strategy is almost identical to DefaultRetryStrategy, except it accepts a vector of error or exception names + * that you want to retry anyway (bypass the retryable definition of the error instance itself) if the retry attempts is less than maxRetries. + */ +class AWS_CORE_API SpecifiedRetryableErrorsRetryStrategy : public DefaultRetryStrategy +{ +public: + SpecifiedRetryableErrorsRetryStrategy(const Aws::Vector<Aws::String>& specifiedRetryableErrors, long maxRetries = 10, long scaleFactor = 25) : + DefaultRetryStrategy(maxRetries, scaleFactor), m_specifiedRetryableErrors(specifiedRetryableErrors) + {} + + bool ShouldRetry(const AWSError<CoreErrors>& error, long attemptedRetries) const override; + +private: + Aws::Vector<Aws::String> m_specifiedRetryableErrors; +}; + +} // namespace Client +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/config/AWSProfileConfigLoader.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/config/AWSProfileConfigLoader.h new file mode 100644 index 0000000000..84c62713da --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/config/AWSProfileConfigLoader.h @@ -0,0 +1,250 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/memory/stl/AWSMap.h> +#include <aws/core/auth/AWSCredentials.h> +#include <aws/core/utils/DateTime.h> +#include <aws/core/utils/threading/ReaderWriterLock.h> + +namespace Aws +{ + namespace Internal + { + class EC2MetadataClient; + } + + namespace Config + { + /** + * Simple data container for a Profile. + */ + class Profile + { + public: + inline const Aws::String& GetName() const { return m_name; } + inline void SetName(const Aws::String& value) { m_name = value; } + inline const Aws::Auth::AWSCredentials& GetCredentials() const { return m_credentials; } + inline void SetCredentials(const Aws::Auth::AWSCredentials& value) { m_credentials = value; } + inline const Aws::String& GetRegion() const { return m_region; } + inline void SetRegion(const Aws::String& value) { m_region = value; } + inline const Aws::String& GetRoleArn() const { return m_roleArn; } + inline void SetRoleArn(const Aws::String& value) { m_roleArn = value; } + inline const Aws::String& GetExternalId() const { return m_externalId; } + inline void SetExternalId(const Aws::String& value) { m_externalId = value; } + inline const Aws::String& GetSourceProfile() const { return m_sourceProfile; } + inline void SetSourceProfile(const Aws::String& value ) { m_sourceProfile = value; } + inline const Aws::String& GetCredentialProcess() const { return m_credentialProcess; } + inline void SetCredentialProcess(const Aws::String& value ) { m_credentialProcess = value; } + inline void SetAllKeyValPairs(const Aws::Map<Aws::String, Aws::String>& map) { m_allKeyValPairs = map; } + inline const Aws::String GetValue(const Aws::String& key) const + { + auto iter = m_allKeyValPairs.find(key); + if (iter == m_allKeyValPairs.end()) return {}; + return iter->second; + } + + private: + Aws::String m_name; + Aws::String m_region; + Aws::Auth::AWSCredentials m_credentials; + Aws::String m_roleArn; + Aws::String m_externalId; + Aws::String m_sourceProfile; + Aws::String m_credentialProcess; + Aws::Map<Aws::String, Aws::String> m_allKeyValPairs; + }; + + /** + * Loads Configuration such as .aws/config, .aws/credentials or ec2 metadata service. + */ + class AWS_CORE_API AWSProfileConfigLoader + { + public: + virtual ~AWSProfileConfigLoader() = default; + + /** + * Load the configuration + */ + bool Load(); + + /** + * Over writes the entire config source with the newly configured profile data. + */ + bool PersistProfiles(const Aws::Map<Aws::String, Aws::Config::Profile>& profiles); + + /** + * Gets all profiles from the configuration file. + */ + inline const Aws::Map<Aws::String, Aws::Config::Profile>& GetProfiles() const { return m_profiles; }; + + /** + * the timestamp from the last time the profile information was loaded from file. + */ + inline const Aws::Utils::DateTime& LastLoadTime() const { return m_lastLoadTime; } + + using ProfilesContainer = Aws::Map<Aws::String, Aws::Config::Profile>; + + protected: + /** + * Subclasses override this method to implement fetching the profiles. + */ + virtual bool LoadInternal() = 0; + + /** + * Subclasses override this method to implement persisting the profiles. Default returns false. + */ + virtual bool PersistInternal(const Aws::Map<Aws::String, Aws::Config::Profile>&) { return false; } + + ProfilesContainer m_profiles; + Aws::Utils::DateTime m_lastLoadTime; + }; + + /** + * Reads configuration from a config file (e.g. $HOME/.aws/config or $HOME/.aws/credentials + */ + class AWS_CORE_API AWSConfigFileProfileConfigLoader : public AWSProfileConfigLoader + { + public: + /** + * fileName - file to load config from + * useProfilePrefix - whether or not the profiles are prefixed with "profile", credentials file is not + * while the config file is. Defaults to off. + */ + AWSConfigFileProfileConfigLoader(const Aws::String& fileName, bool useProfilePrefix = false); + + virtual ~AWSConfigFileProfileConfigLoader() = default; + + /** + * File path being used for the config loader. + */ + const Aws::String& GetFileName() const { return m_fileName; } + + /** + * Give loader the ability to change the file path to load config from. + * This can avoid creating new loader object if the file changed. + */ + void SetFileName(const Aws::String& fileName) { m_fileName = fileName; } + + protected: + virtual bool LoadInternal() override; + virtual bool PersistInternal(const Aws::Map<Aws::String, Aws::Config::Profile>&) override; + + private: + Aws::String m_fileName; + bool m_useProfilePrefix; + }; + + static const char* const INSTANCE_PROFILE_KEY = "InstanceProfile"; + + /** + * Loads configuration from the EC2 Metadata Service + */ + class AWS_CORE_API EC2InstanceProfileConfigLoader : public AWSProfileConfigLoader + { + public: + /** + * If client is nullptr, the default EC2MetadataClient will be created. + */ + EC2InstanceProfileConfigLoader(const std::shared_ptr<Aws::Internal::EC2MetadataClient>& = nullptr); + + virtual ~EC2InstanceProfileConfigLoader() = default; + + protected: + virtual bool LoadInternal() override; + + private: + std::shared_ptr<Aws::Internal::EC2MetadataClient> m_ec2metadataClient; + }; + + /** + * Stores the contents of config file and credentials file to avoid multiple file readings. + * At the same time provides the flexibility to reload from file. + */ + class AWS_CORE_API ConfigAndCredentialsCacheManager + { + public: + ConfigAndCredentialsCacheManager(); + + void ReloadConfigFile(); + + void ReloadCredentialsFile(); + + bool HasConfigProfile(const Aws::String& profileName) const; + + /** + * Returns cached config profile with the specified profile name. + * Using copy instead of const reference to avoid reading bad contents due to thread contention. + */ + Aws::Config::Profile GetConfigProfile(const Aws::String& profileName) const; + + /** + * Returns cached config profiles + * Using copy instead of const reference to avoid reading bad contents due to thread contention. + */ + Aws::Map<Aws::String, Aws::Config::Profile> GetConfigProfiles() const; + + /** + * Returns cached config value with the specified profile name and key. + * Using copy instead of const reference to avoid reading bad contents due to thread contention. + */ + Aws::String GetConfig(const Aws::String& profileName, const Aws::String& key) const; + + bool HasCredentialsProfile(const Aws::String& profileName) const; + /** + * Returns cached credentials profile with the specified profile name. + * Using copy instead of const reference to avoid reading bad contents due to thread contention. + */ + Aws::Config::Profile GetCredentialsProfile(const Aws::String& profileName) const; + + /** + * Returns cached credentials profiles. + * Using copy instead of const reference to avoid reading bad contents due to thread contention. + */ + Aws::Map<Aws::String, Aws::Config::Profile> GetCredentialsProfiles() const; + + /** + * Returns cached credentials with the specified profile name. + * Using copy instead of const reference to avoid reading bad contents due to thread contention. + */ + Aws::Auth::AWSCredentials GetCredentials(const Aws::String& profileName) const; + + private: + mutable Aws::Utils::Threading::ReaderWriterLock m_credentialsLock; + Aws::Config::AWSConfigFileProfileConfigLoader m_credentialsFileLoader; + mutable Aws::Utils::Threading::ReaderWriterLock m_configLock; + Aws::Config::AWSConfigFileProfileConfigLoader m_configFileLoader; + }; + + AWS_CORE_API void InitConfigAndCredentialsCacheManager(); + + AWS_CORE_API void CleanupConfigAndCredentialsCacheManager(); + + AWS_CORE_API void ReloadCachedConfigFile(); + + AWS_CORE_API void ReloadCachedCredentialsFile(); + + AWS_CORE_API bool HasCachedConfigProfile(const Aws::String& profileName); + + AWS_CORE_API Aws::Config::Profile GetCachedConfigProfile(const Aws::String& profileName); + + AWS_CORE_API Aws::Map<Aws::String, Aws::Config::Profile> GetCachedConfigProfiles(); + + AWS_CORE_API Aws::String GetCachedConfigValue(const Aws::String& profileName, const Aws::String& key); + + AWS_CORE_API Aws::String GetCachedConfigValue(const Aws::String& key); + + AWS_CORE_API bool HasCachedCredentialsProfile(const Aws::String &profileName); + + AWS_CORE_API Aws::Config::Profile GetCachedCredentialsProfile(const Aws::String& profileName); + + AWS_CORE_API Aws::Auth::AWSCredentials GetCachedCredentials(const Aws::String& profileName); + + AWS_CORE_API Aws::Map<Aws::String, Aws::Config::Profile> GetCachedCredentialsProfiles(); + + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/external/cjson/cJSON.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/external/cjson/cJSON.h new file mode 100644 index 0000000000..9a010a67db --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/external/cjson/cJSON.h @@ -0,0 +1,289 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 7 +#define CJSON_VERSION_PATCH 7 + +#include <stddef.h> + +/* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct cJSON +{ + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +typedef struct cJSON_Hooks +{ + void *(*malloc_fn)(size_t sz); + void (*free_fn)(void *ptr); +} cJSON_Hooks; + +typedef int cJSON_bool; + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols +CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) +CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + +For *nix builds that support visibility attribute, you can define similar behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + +*/ + +/* Decide calling convention based on the cmake parameters defined in C++ SDK. */ +#ifdef USE_IMPORT_EXPORT +#ifdef AWS_CORE_EXPORTS +#define CJSON_EXPORT_SYMBOLS +#else +#define CJSON_IMPORT_SYMBOLS +#endif // AWS_CORE_EXPORTS +#else +#define CJSON_HIDE_SYMBOLS +#endif // USE_IMPORT_EXPORT + +/* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type __stdcall +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall +#endif +#else /* !WIN32 */ +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + +/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + +/* returns the version of cJSON as a string */ +CJSON_PUBLIC(const char*) cJSON_Version(void); + +/* Supply malloc, realloc and free functions to cJSON */ +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); + +/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); + +/* Render a cJSON entity to text for transfer/storage. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. */ +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); +/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ +/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); +/* Delete a cJSON entity and all subentities. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); + +/* Returns the number of items in an array (or object). */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); +/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); +/* Get item "string" from object. Case insensitive. */ +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + +/* Check if the item is a string and return its valuestring */ +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item); + +/* These functions check the type of an item */ +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); + +/* These calls create a cJSON item of the appropriate type. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); +CJSON_PUBLIC(cJSON *) cJSON_CreateInt64(long long num); +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); +/* raw json */ +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + +/* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); +/* Create an object/arrray that only references it's elements so + * they will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); + +/* These utilities create an Array of count items. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); + +/* Append item to the specified array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + +/* Remove/Detach items from Arrays/Objects. */ +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + +/* Update array items. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will +need to be released. With recurse!=0, it will duplicate any children connected to the item. +The item->next and ->prev pointers are always zero on return from Duplicate. */ +/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + + +CJSON_PUBLIC(void) cJSON_Minify(char *json); + +/* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) +/* helper for the cJSON_SetNumberValue macro */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) + +/* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + +/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ +CJSON_PUBLIC(void *) cJSON_malloc(size_t size); +CJSON_PUBLIC(void) cJSON_free(void *object); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/external/tinyxml2/tinyxml2.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/external/tinyxml2/tinyxml2.h new file mode 100644 index 0000000000..3721ed1f97 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/external/tinyxml2/tinyxml2.h @@ -0,0 +1,2292 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ +/* +This file has been modified from its original version by Amazon: + (1) Memory management operations use aws memory management api + (2) Import-export preprocessor logic tweaked for better integration into core library + (3) Wrapped everything in Amazon namespace to prevent static linking issues if the user includes a version of this code through another dependency +*/ +#ifndef TINYXML2_INCLUDED +#define TINYXML2_INCLUDED + +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +# include <ctype.h> +# include <limits.h> +# include <stdio.h> +# include <stdlib.h> +# include <string.h> +# if defined(__PS3__) +# include <stddef.h> +# endif +#else +# include <cctype> +# include <climits> +# include <cstdio> +# include <cstdlib> +# include <cstring> +#endif +#include <stdint.h> + +#include <aws/core/utils/memory/AWSMemory.h> + +/* + TODO: intern strings instead of allocation. +*/ +/* + gcc: + g++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe + + Formatting, Artistic Style: + AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h +*/ + +#if defined( _DEBUG ) || defined (__DEBUG__) +# ifndef DEBUG +# define DEBUG +# endif +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4251) +#endif + +#ifdef _WIN32 + #ifdef USE_IMPORT_EXPORT + #ifdef AWS_CORE_EXPORTS + #define TINYXML2_LIB __declspec(dllexport) + #else + #define TINYXML2_LIB __declspec(dllimport) + #endif // AWS_CORE_EXPORTS + #endif // USE_IMPORT_EXPORT +#elif __GNUC__ >= 4 + #define TINYXML2_LIB __attribute__((visibility("default"))) +#endif // _WIN32 + +#ifndef TINYXML2_LIB + #define TINYXML2_LIB +#endif // TINYXML2_LIB + +#if defined(DEBUG) +# if defined(_MSC_VER) +# // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like +# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); } +# elif defined (ANDROID_NDK) +# include <android/log.h> +# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } +# else +# include <assert.h> +# define TIXMLASSERT assert +# endif +#else +# define TIXMLASSERT( x ) {} +#endif + + +/* Versioning, past 1.0.14: + http://semver.org/ +*/ +static const int TIXML2_MAJOR_VERSION = 6; +static const int TIXML2_MINOR_VERSION = 1; +static const int TIXML2_PATCH_VERSION = 0; + +#define TINYXML2_MAJOR_VERSION 6 +#define TINYXML2_MINOR_VERSION 1 +#define TINYXML2_PATCH_VERSION 0 + +namespace Aws +{ +namespace External +{ +namespace tinyxml2 +{ +class XMLDocument; +class XMLElement; +class XMLAttribute; +class XMLComment; +class XMLText; +class XMLDeclaration; +class XMLUnknown; +class XMLPrinter; + +static const char* ALLOCATION_TAG = "AWS::TinyXML"; + +/* + A class that wraps strings. Normally stores the start and end + pointers into the XML file itself, and will apply normalization + and entity translation if actually read. Can also store (and memory + manage) a traditional char[] +*/ +class TINYXML2_LIB StrPair +{ +public: + enum { + NEEDS_ENTITY_PROCESSING = 0x01, + NEEDS_NEWLINE_NORMALIZATION = 0x02, + NEEDS_WHITESPACE_COLLAPSING = 0x04, + + TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_NAME = 0, + ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + COMMENT = NEEDS_NEWLINE_NORMALIZATION + }; + + StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} + ~StrPair(); + + void Set( char* start, char* end, int flags ) { + TIXMLASSERT( start ); + TIXMLASSERT( end ); + Reset(); + _start = start; + _end = end; + _flags = flags | NEEDS_FLUSH; + } + + const char* GetStr(); + + bool Empty() const { + return _start == _end; + } + + void SetInternedStr( const char* str ) { + Reset(); + _start = const_cast<char*>(str); + } + + void SetStr( const char* str, int flags=0 ); + + char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr ); + char* ParseName( char* in ); + + void TransferTo( StrPair* other ); + void Reset(); + +private: + void CollapseWhitespace(); + + enum { + NEEDS_FLUSH = 0x100, + NEEDS_DELETE = 0x200 + }; + + int _flags; + char* _start; + char* _end; + + StrPair( const StrPair& other ); // not supported + void operator=( StrPair& other ); // not supported, use TransferTo() +}; + + +/* + A dynamic array of Plain Old Data. Doesn't support constructors, etc. + Has a small initial memory pool, so that low or no usage will not + cause a call to new/delete +*/ +template <class T, int INITIAL_SIZE> +class DynArray +{ +public: + DynArray() : + _mem( _pool ), + _allocated( INITIAL_SIZE ), + _size( 0 ) + { + } + + ~DynArray() { + if ( _mem != _pool ) { + Aws::DeleteArray<T>(_mem); + } + } + + void Clear() { + _size = 0; + } + + void Push( T t ) { + TIXMLASSERT( _size < INT_MAX ); + EnsureCapacity( _size+1 ); + _mem[_size] = t; + ++_size; + } + + T* PushArr( int count ) { + TIXMLASSERT( count >= 0 ); + TIXMLASSERT( _size <= INT_MAX - count ); + EnsureCapacity( _size+count ); + T* ret = &_mem[_size]; + _size += count; + return ret; + } + + T Pop() { + TIXMLASSERT( _size > 0 ); + --_size; + return _mem[_size]; + } + + void PopArr( int count ) { + TIXMLASSERT( _size >= count ); + _size -= count; + } + + bool Empty() const { + return _size == 0; + } + + T& operator[](int i) { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& operator[](int i) const { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& PeekTop() const { + TIXMLASSERT( _size > 0 ); + return _mem[ _size - 1]; + } + + int Size() const { + TIXMLASSERT( _size >= 0 ); + return _size; + } + + int Capacity() const { + TIXMLASSERT( _allocated >= INITIAL_SIZE ); + return _allocated; + } + + void SwapRemove(int i) { + TIXMLASSERT(i >= 0 && i < _size); + TIXMLASSERT(_size > 0); + _mem[i] = _mem[_size - 1]; + --_size; + } + + const T* Mem() const { + TIXMLASSERT( _mem ); + return _mem; + } + + T* Mem() { + TIXMLASSERT( _mem ); + return _mem; + } + +private: + DynArray( const DynArray& ); // not supported + void operator=( const DynArray& ); // not supported + + void EnsureCapacity( int cap ) { + TIXMLASSERT( cap > 0 ); + if ( cap > _allocated ) { + TIXMLASSERT( cap <= INT_MAX / 2 ); + int newAllocated = cap * 2; + T* newMem = Aws::NewArray<T>(newAllocated, ALLOCATION_TAG); + TIXMLASSERT( newAllocated >= _size ); + memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs + if ( _mem != _pool ) { + Aws::DeleteArray<T>(_mem); + } + _mem = newMem; + _allocated = newAllocated; + } + } + + T* _mem; + T _pool[INITIAL_SIZE]; + int _allocated; // objects allocated + int _size; // number objects in use +}; + + +/* + Parent virtual class of a pool for fast allocation + and deallocation of objects. +*/ +class MemPool +{ +public: + MemPool() {} + virtual ~MemPool() {} + + virtual int ItemSize() const = 0; + virtual void* Alloc() = 0; + virtual void Free( void* ) = 0; + virtual void SetTracked() = 0; + virtual void Clear() = 0; +}; + + +/* + Template child class to create pools of the correct type. +*/ +template< int ITEM_SIZE > +class MemPoolT : public MemPool +{ +public: + MemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} + ~MemPoolT() { + Clear(); + } + + void Clear() { + // Delete the blocks. + while( !_blockPtrs.Empty()) { + Block* lastBlock = _blockPtrs.Pop(); + Aws::Delete(lastBlock); + } + _root = 0; + _currentAllocs = 0; + _nAllocs = 0; + _maxAllocs = 0; + _nUntracked = 0; + } + + virtual int ItemSize() const { + return ITEM_SIZE; + } + int CurrentAllocs() const { + return _currentAllocs; + } + + virtual void* Alloc() { + if ( !_root ) { + // Need a new block. + Block* block = Aws::New<Block>(ALLOCATION_TAG); + _blockPtrs.Push( block ); + + Item* blockItems = block->items; + for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) { + blockItems[i].next = &(blockItems[i + 1]); + } + blockItems[ITEMS_PER_BLOCK - 1].next = 0; + _root = blockItems; + } + Item* const result = _root; + TIXMLASSERT( result != 0 ); + _root = _root->next; + + ++_currentAllocs; + if ( _currentAllocs > _maxAllocs ) { + _maxAllocs = _currentAllocs; + } + ++_nAllocs; + ++_nUntracked; + return result; + } + + virtual void Free( void* mem ) { + if ( !mem ) { + return; + } + --_currentAllocs; + Item* item = static_cast<Item*>( mem ); +#ifdef DEBUG + memset( item, 0xfe, sizeof( *item ) ); +#endif + item->next = _root; + _root = item; + } + void Trace( const char* name ) { + printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", + name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs, + ITEM_SIZE, _nAllocs, _blockPtrs.Size() ); + } + + void SetTracked() { + --_nUntracked; + } + + int Untracked() const { + return _nUntracked; + } + + // This number is perf sensitive. 4k seems like a good tradeoff on my machine. + // The test file is large, 170k. + // Release: VS2010 gcc(no opt) + // 1k: 4000 + // 2k: 4000 + // 4k: 3900 21000 + // 16k: 5200 + // 32k: 4300 + // 64k: 4000 21000 + // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK + // in private part if ITEMS_PER_BLOCK is private + enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE }; + +private: + MemPoolT( const MemPoolT& ); // not supported + void operator=( const MemPoolT& ); // not supported + + union Item { + Item* next; + char itemData[ITEM_SIZE]; + }; + struct Block { + Item items[ITEMS_PER_BLOCK]; + }; + DynArray< Block*, 10 > _blockPtrs; + Item* _root; + + int _currentAllocs; + int _nAllocs; + int _maxAllocs; + int _nUntracked; +}; + + + +/** + Implements the interface to the "Visitor pattern" (see the Accept() method.) + If you call the Accept() method, it requires being passed a XMLVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs + are simply called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, <b>no children of this node or its siblings</b> will be visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the XMLDocument, although all nodes support visiting. + + You should never change the document from a callback. + + @sa XMLNode::Accept() +*/ +class TINYXML2_LIB XMLVisitor +{ +public: + virtual ~XMLVisitor() {} + + /// Visit a document. + virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { + return true; + } + /// Visit a document. + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + /// Visit an element. + virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { + return true; + } + /// Visit an element. + virtual bool VisitExit( const XMLElement& /*element*/ ) { + return true; + } + + /// Visit a declaration. + virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { + return true; + } + /// Visit a text node. + virtual bool Visit( const XMLText& /*text*/ ) { + return true; + } + /// Visit a comment node. + virtual bool Visit( const XMLComment& /*comment*/ ) { + return true; + } + /// Visit an unknown node. + virtual bool Visit( const XMLUnknown& /*unknown*/ ) { + return true; + } +}; + +// WARNING: must match XMLDocument::_errorNames[] +enum XMLError { + XML_SUCCESS = 0, + XML_NO_ATTRIBUTE, + XML_WRONG_ATTRIBUTE_TYPE, + XML_ERROR_FILE_NOT_FOUND, + XML_ERROR_FILE_COULD_NOT_BE_OPENED, + XML_ERROR_FILE_READ_ERROR, + UNUSED_XML_ERROR_ELEMENT_MISMATCH, // remove at next major version + XML_ERROR_PARSING_ELEMENT, + XML_ERROR_PARSING_ATTRIBUTE, + UNUSED_XML_ERROR_IDENTIFYING_TAG, // remove at next major version + XML_ERROR_PARSING_TEXT, + XML_ERROR_PARSING_CDATA, + XML_ERROR_PARSING_COMMENT, + XML_ERROR_PARSING_DECLARATION, + XML_ERROR_PARSING_UNKNOWN, + XML_ERROR_EMPTY_DOCUMENT, + XML_ERROR_MISMATCHED_ELEMENT, + XML_ERROR_PARSING, + XML_CAN_NOT_CONVERT_TEXT, + XML_NO_TEXT_NODE, + + XML_ERROR_COUNT +}; + + +/* + Utility functionality. +*/ +class TINYXML2_LIB XMLUtil +{ +public: + static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) { + TIXMLASSERT( p ); + + while( IsWhiteSpace(*p) ) { + if (curLineNumPtr && *p == '\n') { + ++(*curLineNumPtr); + } + ++p; + } + TIXMLASSERT( p ); + return p; + } + static char* SkipWhiteSpace( char* p, int* curLineNumPtr ) { + return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p), curLineNumPtr ) ); + } + + // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't + // correct, but simple, and usually works. + static bool IsWhiteSpace( char p ) { + return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) ); + } + + inline static bool IsNameStartChar( unsigned char ch ) { + if ( ch >= 128 ) { + // This is a heuristic guess in attempt to not implement Unicode-aware isalpha() + return true; + } + if ( isalpha( ch ) ) { + return true; + } + return ch == ':' || ch == '_'; + } + + inline static bool IsNameChar( unsigned char ch ) { + return IsNameStartChar( ch ) + || isdigit( ch ) + || ch == '.' + || ch == '-'; + } + + inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { + if ( p == q ) { + return true; + } + TIXMLASSERT( p ); + TIXMLASSERT( q ); + TIXMLASSERT( nChar >= 0 ); + return strncmp( p, q, nChar ) == 0; + } + + inline static bool IsUTF8Continuation( char p ) { + return ( p & 0x80 ) != 0; + } + + static const char* ReadBOM( const char* p, bool* hasBOM ); + // p is the starting location, + // the UTF-8 value of the entity will be placed in value, and length filled in. + static const char* GetCharacterRef( const char* p, char* value, int* length ); + static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); + + // converts primitive types to strings + static void ToStr( int v, char* buffer, int bufferSize ); + static void ToStr( unsigned v, char* buffer, int bufferSize ); + static void ToStr( bool v, char* buffer, int bufferSize ); + static void ToStr( float v, char* buffer, int bufferSize ); + static void ToStr( double v, char* buffer, int bufferSize ); + static void ToStr(int64_t v, char* buffer, int bufferSize); + + // converts strings to primitive types + static bool ToInt( const char* str, int* value ); + static bool ToUnsigned( const char* str, unsigned* value ); + static bool ToBool( const char* str, bool* value ); + static bool ToFloat( const char* str, float* value ); + static bool ToDouble( const char* str, double* value ); + static bool ToInt64(const char* str, int64_t* value); + + // Changes what is serialized for a boolean value. + // Default to "true" and "false". Shouldn't be changed + // unless you have a special testing or compatibility need. + // Be careful: static, global, & not thread safe. + // Be sure to set static const memory as parameters. + static void SetBoolSerialization(const char* writeTrue, const char* writeFalse); + +private: + static const char* writeBoolTrue; + static const char* writeBoolFalse; +}; + + +/** XMLNode is a base class for every object that is in the + XML Document Object Model (DOM), except XMLAttributes. + Nodes have siblings, a parent, and children which can + be navigated. A node is always in a XMLDocument. + The type of a XMLNode can be queried, and it can + be cast to its more defined type. + + A XMLDocument allocates memory for all its Nodes. + When the XMLDocument gets deleted, all its Nodes + will also be deleted. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + @endverbatim +*/ +class TINYXML2_LIB XMLNode +{ + friend class XMLDocument; + friend class XMLElement; +public: + + /// Get the XMLDocument that owns this XMLNode. + const XMLDocument* GetDocument() const { + TIXMLASSERT( _document ); + return _document; + } + /// Get the XMLDocument that owns this XMLNode. + XMLDocument* GetDocument() { + TIXMLASSERT( _document ); + return _document; + } + + /// Safely cast to an Element, or null. + virtual XMLElement* ToElement() { + return 0; + } + /// Safely cast to Text, or null. + virtual XMLText* ToText() { + return 0; + } + /// Safely cast to a Comment, or null. + virtual XMLComment* ToComment() { + return 0; + } + /// Safely cast to a Document, or null. + virtual XMLDocument* ToDocument() { + return 0; + } + /// Safely cast to a Declaration, or null. + virtual XMLDeclaration* ToDeclaration() { + return 0; + } + /// Safely cast to an Unknown, or null. + virtual XMLUnknown* ToUnknown() { + return 0; + } + + virtual const XMLElement* ToElement() const { + return 0; + } + virtual const XMLText* ToText() const { + return 0; + } + virtual const XMLComment* ToComment() const { + return 0; + } + virtual const XMLDocument* ToDocument() const { + return 0; + } + virtual const XMLDeclaration* ToDeclaration() const { + return 0; + } + virtual const XMLUnknown* ToUnknown() const { + return 0; + } + + /** The meaning of 'value' changes for the specific type. + @verbatim + Document: empty (NULL is returned, not an empty string) + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + const char* Value() const; + + /** Set the Value of an XML node. + @sa Value() + */ + void SetValue( const char* val, bool staticMem=false ); + + /// Gets the line number the node is in, if the document was parsed from a file. + int GetLineNum() const { return _parseLineNum; } + + /// Get the parent of this node on the DOM. + const XMLNode* Parent() const { + return _parent; + } + + XMLNode* Parent() { + return _parent; + } + + /// Returns true if this node has no children. + bool NoChildren() const { + return !_firstChild; + } + + /// Get the first child node, or null if none exists. + const XMLNode* FirstChild() const { + return _firstChild; + } + + XMLNode* FirstChild() { + return _firstChild; + } + + /** Get the first child element, or optionally the first child + element with the specified name. + */ + const XMLElement* FirstChildElement( const char* name = 0 ) const; + + XMLElement* FirstChildElement( const char* name = 0 ) { + return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( name )); + } + + /// Get the last child node, or null if none exists. + const XMLNode* LastChild() const { + return _lastChild; + } + + XMLNode* LastChild() { + return _lastChild; + } + + /** Get the last child element or optionally the last child + element with the specified name. + */ + const XMLElement* LastChildElement( const char* name = 0 ) const; + + XMLElement* LastChildElement( const char* name = 0 ) { + return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(name) ); + } + + /// Get the previous (left) sibling node of this node. + const XMLNode* PreviousSibling() const { + return _prev; + } + + XMLNode* PreviousSibling() { + return _prev; + } + + /// Get the previous (left) sibling element of this node, with an optionally supplied name. + const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ; + + XMLElement* PreviousSiblingElement( const char* name = 0 ) { + return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( name ) ); + } + + /// Get the next (right) sibling node of this node. + const XMLNode* NextSibling() const { + return _next; + } + + XMLNode* NextSibling() { + return _next; + } + + /// Get the next (right) sibling element of this node, with an optionally supplied name. + const XMLElement* NextSiblingElement( const char* name = 0 ) const; + + XMLElement* NextSiblingElement( const char* name = 0 ) { + return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( name ) ); + } + + /** + Add a child node as the last (right) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertEndChild( XMLNode* addThis ); + + XMLNode* LinkEndChild( XMLNode* addThis ) { + return InsertEndChild( addThis ); + } + /** + Add a child node as the first (left) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertFirstChild( XMLNode* addThis ); + /** + Add a node after the specified child node. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the afterThis node + is not a child of this node, or if the node does not + belong to the same document. + */ + XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); + + /** + Delete all the children of this node. + */ + void DeleteChildren(); + + /** + Delete a child of this node. + */ + void DeleteChild( XMLNode* node ); + + /** + Make a copy of this node, but not its children. + You may pass in a Document pointer that will be + the owner of the new Node. If the 'document' is + null, then the node returned will be allocated + from the current Document. (this->GetDocument()) + + Note: if called on a XMLDocument, this will return null. + */ + virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; + + /** + Make a copy of this node and all its children. + + If the 'target' is null, then the nodes will + be allocated in the current document. If 'target' + is specified, the memory will be allocated is the + specified XMLDocument. + + NOTE: This is probably not the correct tool to + copy a document, since XMLDocuments can have multiple + top level XMLNodes. You probably want to use + XMLDocument::DeepCopy() + */ + XMLNode* DeepClone( XMLDocument* target ) const; + + /** + Test if 2 nodes are the same, but don't test children. + The 2 nodes do not need to be in the same Document. + + Note: if called on a XMLDocument, this will return false. + */ + virtual bool ShallowEqual( const XMLNode* compare ) const = 0; + + /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the XMLVisitor interface. + + This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + XMLPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept( XMLVisitor* visitor ) const = 0; + + /** + Set user data into the XMLNode. TinyXML-2 in + no way processes or interprets user data. + It is initially 0. + */ + void SetUserData(void* userData) { _userData = userData; } + + /** + Get user data set into the XMLNode. TinyXML-2 in + no way processes or interprets user data. + It is initially 0. + */ + void* GetUserData() const { return _userData; } + +protected: + XMLNode( XMLDocument* ); + virtual ~XMLNode(); + + virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); + + XMLDocument* _document; + XMLNode* _parent; + mutable StrPair _value; + int _parseLineNum; + + XMLNode* _firstChild; + XMLNode* _lastChild; + + XMLNode* _prev; + XMLNode* _next; + + void* _userData; + +private: + MemPool* _memPool; + void Unlink( XMLNode* child ); + static void DeleteNode( XMLNode* node ); + void InsertChildPreamble( XMLNode* insertThis ) const; + const XMLElement* ToElementWithName( const char* name ) const; + + XMLNode( const XMLNode& ); // not supported + XMLNode& operator=( const XMLNode& ); // not supported +}; + + +/** XML text. + + Note that a text node can have child element nodes, for example: + @verbatim + <root>This is <b>bold</b></root> + @endverbatim + + A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCData() and query it with CData(). +*/ +class TINYXML2_LIB XMLText : public XMLNode +{ + friend class XMLDocument; +public: + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLText* ToText() { + return this; + } + virtual const XMLText* ToText() const { + return this; + } + + /// Declare whether this should be CDATA or standard text. + void SetCData( bool isCData ) { + _isCData = isCData; + } + /// Returns true if this is a CDATA text element. + bool CData() const { + return _isCData; + } + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} + virtual ~XMLText() {} + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + bool _isCData; + + XMLText( const XMLText& ); // not supported + XMLText& operator=( const XMLText& ); // not supported +}; + + +/** An XML Comment. */ +class TINYXML2_LIB XMLComment : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLComment* ToComment() { + return this; + } + virtual const XMLComment* ToComment() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLComment( XMLDocument* doc ); + virtual ~XMLComment(); + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); + +private: + XMLComment( const XMLComment& ); // not supported + XMLComment& operator=( const XMLComment& ); // not supported +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + <?xml version="1.0" standalone="yes"?> + @endverbatim + + TinyXML-2 will happily read or write files without a declaration, + however. + + The text of the declaration isn't interpreted. It is parsed + and written as a string. +*/ +class TINYXML2_LIB XMLDeclaration : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLDeclaration* ToDeclaration() { + return this; + } + virtual const XMLDeclaration* ToDeclaration() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLDeclaration( XMLDocument* doc ); + virtual ~XMLDeclaration(); + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + XMLDeclaration( const XMLDeclaration& ); // not supported + XMLDeclaration& operator=( const XMLDeclaration& ); // not supported +}; + + +/** Any tag that TinyXML-2 doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into XMLUnknowns. +*/ +class TINYXML2_LIB XMLUnknown : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLUnknown* ToUnknown() { + return this; + } + virtual const XMLUnknown* ToUnknown() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + XMLUnknown( XMLDocument* doc ); + virtual ~XMLUnknown(); + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + XMLUnknown( const XMLUnknown& ); // not supported + XMLUnknown& operator=( const XMLUnknown& ); // not supported +}; + + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not XMLNodes. You may only query the + Next() attribute in a list. +*/ +class TINYXML2_LIB XMLAttribute +{ + friend class XMLElement; +public: + /// The name of the attribute. + const char* Name() const; + + /// The value of the attribute. + const char* Value() const; + + /// Gets the line number the attribute is in, if the document was parsed from a file. + int GetLineNum() const { return _parseLineNum; } + + /// The next attribute in the list. + const XMLAttribute* Next() const { + return _next; + } + + /** IntValue interprets the attribute as an integer, and returns the value. + If the value isn't an integer, 0 will be returned. There is no error checking; + use QueryIntValue() if you need error checking. + */ + int IntValue() const { + int i = 0; + QueryIntValue(&i); + return i; + } + + int64_t Int64Value() const { + int64_t i = 0; + QueryInt64Value(&i); + return i; + } + + /// Query as an unsigned integer. See IntValue() + unsigned UnsignedValue() const { + unsigned i=0; + QueryUnsignedValue( &i ); + return i; + } + /// Query as a boolean. See IntValue() + bool BoolValue() const { + bool b=false; + QueryBoolValue( &b ); + return b; + } + /// Query as a double. See IntValue() + double DoubleValue() const { + double d=0; + QueryDoubleValue( &d ); + return d; + } + /// Query as a float. See IntValue() + float FloatValue() const { + float f=0; + QueryFloatValue( &f ); + return f; + } + + /** QueryIntValue interprets the attribute as an integer, and returns the value + in the provided parameter. The function will return XML_SUCCESS on success, + and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. + */ + XMLError QueryIntValue( int* value ) const; + /// See QueryIntValue + XMLError QueryUnsignedValue( unsigned int* value ) const; + /// See QueryIntValue + XMLError QueryInt64Value(int64_t* value) const; + /// See QueryIntValue + XMLError QueryBoolValue( bool* value ) const; + /// See QueryIntValue + XMLError QueryDoubleValue( double* value ) const; + /// See QueryIntValue + XMLError QueryFloatValue( float* value ) const; + + /// Set the attribute to a string value. + void SetAttribute( const char* value ); + /// Set the attribute to value. + void SetAttribute( int value ); + /// Set the attribute to value. + void SetAttribute( unsigned value ); + /// Set the attribute to value. + void SetAttribute(int64_t value); + /// Set the attribute to value. + void SetAttribute( bool value ); + /// Set the attribute to value. + void SetAttribute( double value ); + /// Set the attribute to value. + void SetAttribute( float value ); + +private: + enum { BUF_SIZE = 200 }; + + XMLAttribute() : _name(), _value(),_parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {} + virtual ~XMLAttribute() {} + + XMLAttribute( const XMLAttribute& ); // not supported + void operator=( const XMLAttribute& ); // not supported + void SetName( const char* name ); + + char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr ); + + mutable StrPair _name; + mutable StrPair _value; + int _parseLineNum; + XMLAttribute* _next; + MemPool* _memPool; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class TINYXML2_LIB XMLElement : public XMLNode +{ + friend class XMLDocument; +public: + /// Get the name of an element (which is the Value() of the node.) + const char* Name() const { + return Value(); + } + /// Set the name of the element. + void SetName( const char* str, bool staticMem=false ) { + SetValue( str, staticMem ); + } + + virtual XMLElement* ToElement() { + return this; + } + virtual const XMLElement* ToElement() const { + return this; + } + virtual bool Accept( XMLVisitor* visitor ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none + exists. For example: + + @verbatim + const char* value = ele->Attribute( "foo" ); + @endverbatim + + The 'value' parameter is normally null. However, if specified, + the attribute will only be returned if the 'name' and 'value' + match. This allow you to write code: + + @verbatim + if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); + @endverbatim + + rather than: + @verbatim + if ( ele->Attribute( "foo" ) ) { + if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); + } + @endverbatim + */ + const char* Attribute( const char* name, const char* value=0 ) const; + + /** Given an attribute name, IntAttribute() returns the value + of the attribute interpreted as an integer. The default + value will be returned if the attribute isn't present, + or if there is an error. (For a method with error + checking, see QueryIntAttribute()). + */ + int IntAttribute(const char* name, int defaultValue = 0) const; + /// See IntAttribute() + unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const; + /// See IntAttribute() + int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const; + /// See IntAttribute() + bool BoolAttribute(const char* name, bool defaultValue = false) const; + /// See IntAttribute() + double DoubleAttribute(const char* name, double defaultValue = 0) const; + /// See IntAttribute() + float FloatAttribute(const char* name, float defaultValue = 0) const; + + /** Given an attribute name, QueryIntAttribute() returns + XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + XMLError QueryIntAttribute( const char* name, int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryIntValue( value ); + } + + /// See QueryIntAttribute() + XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryUnsignedValue( value ); + } + + /// See QueryIntAttribute() + XMLError QueryInt64Attribute(const char* name, int64_t* value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + return a->QueryInt64Value(value); + } + + /// See QueryIntAttribute() + XMLError QueryBoolAttribute( const char* name, bool* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryBoolValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryDoubleAttribute( const char* name, double* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryDoubleValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryFloatAttribute( const char* name, float* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryFloatValue( value ); + } + + + /** Given an attribute name, QueryAttribute() returns + XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. It is overloaded for the primitive types, + and is a generally more convenient replacement of + QueryIntAttribute() and related functions. + + If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + int QueryAttribute( const char* name, int* value ) const { + return QueryIntAttribute( name, value ); + } + + int QueryAttribute( const char* name, unsigned int* value ) const { + return QueryUnsignedAttribute( name, value ); + } + + int QueryAttribute(const char* name, int64_t* value) const { + return QueryInt64Attribute(name, value); + } + + int QueryAttribute( const char* name, bool* value ) const { + return QueryBoolAttribute( name, value ); + } + + int QueryAttribute( const char* name, double* value ) const { + return QueryDoubleAttribute( name, value ); + } + + int QueryAttribute( const char* name, float* value ) const { + return QueryFloatAttribute( name, value ); + } + + /// Sets the named attribute to value. + void SetAttribute( const char* name, const char* value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, int value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, unsigned value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + + /// Sets the named attribute to value. + void SetAttribute(const char* name, int64_t value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + + /// Sets the named attribute to value. + void SetAttribute( const char* name, bool value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, double value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, float value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + + /** + Delete an attribute. + */ + void DeleteAttribute( const char* name ); + + /// Return the first attribute in the list. + const XMLAttribute* FirstAttribute() const { + return _rootAttribute; + } + /// Query a specific attribute in the list. + const XMLAttribute* FindAttribute( const char* name ) const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the XMLText child + and accessing it directly. + + If the first child of 'this' is a XMLText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + <foo>This is text</foo> + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + <foo><b>This is text</b></foo> + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + <foo>This is <b>text</b></foo> + @endverbatim + GetText() will return "This is ". + */ + const char* GetText() const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, SetText() is limited compared to creating an XMLText child + and mutating it directly. + + If the first child of 'this' is a XMLText, SetText() sets its value to + the given string, otherwise it will create a first child that is an XMLText. + + This is a convenient method for setting the text of simple contained text: + @verbatim + <foo>This is text</foo> + fooElement->SetText( "Hullaballoo!" ); + <foo>Hullaballoo!</foo> + @endverbatim + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + <foo><b>This is text</b></foo> + @endverbatim + + then it will not change "This is text", but rather prefix it with a text element: + @verbatim + <foo>Hullaballoo!<b>This is text</b></foo> + @endverbatim + + For this XML: + @verbatim + <foo /> + @endverbatim + SetText() will generate + @verbatim + <foo>Hullaballoo!</foo> + @endverbatim + */ + void SetText( const char* inText ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( int value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( unsigned value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText(int64_t value); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( bool value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( double value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( float value ); + + /** + Convenience method to query the value of a child text node. This is probably best + shown by example. Given you have a document is this form: + @verbatim + <point> + <x>1</x> + <y>1.4</y> + </point> + @endverbatim + + The QueryIntText() and similar functions provide a safe and easier way to get to the + "value" of x and y. + + @verbatim + int x = 0; + float y = 0; // types of x and y are contrived for example + const XMLElement* xElement = pointElement->FirstChildElement( "x" ); + const XMLElement* yElement = pointElement->FirstChildElement( "y" ); + xElement->QueryIntText( &x ); + yElement->QueryFloatText( &y ); + @endverbatim + + @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted + to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. + + */ + XMLError QueryIntText( int* ival ) const; + /// See QueryIntText() + XMLError QueryUnsignedText( unsigned* uval ) const; + /// See QueryIntText() + XMLError QueryInt64Text(int64_t* uval) const; + /// See QueryIntText() + XMLError QueryBoolText( bool* bval ) const; + /// See QueryIntText() + XMLError QueryDoubleText( double* dval ) const; + /// See QueryIntText() + XMLError QueryFloatText( float* fval ) const; + + int IntText(int defaultValue = 0) const; + + /// See QueryIntText() + unsigned UnsignedText(unsigned defaultValue = 0) const; + /// See QueryIntText() + int64_t Int64Text(int64_t defaultValue = 0) const; + /// See QueryIntText() + bool BoolText(bool defaultValue = false) const; + /// See QueryIntText() + double DoubleText(double defaultValue = 0) const; + /// See QueryIntText() + float FloatText(float defaultValue = 0) const; + + // internal: + enum ElementClosingType { + OPEN, // <foo> + CLOSED, // <foo/> + CLOSING // </foo> + }; + ElementClosingType ClosingType() const { + return _closingType; + } + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + XMLElement( XMLDocument* doc ); + virtual ~XMLElement(); + XMLElement( const XMLElement& ); // not supported + void operator=( const XMLElement& ); // not supported + + XMLAttribute* FindAttribute( const char* name ) { + return const_cast<XMLAttribute*>(const_cast<const XMLElement*>(this)->FindAttribute( name )); + } + XMLAttribute* FindOrCreateAttribute( const char* name ); + //void LinkAttribute( XMLAttribute* attrib ); + char* ParseAttributes( char* p, int* curLineNumPtr ); + static void DeleteAttribute( XMLAttribute* attribute ); + XMLAttribute* CreateAttribute(); + + enum { BUF_SIZE = 200 }; + ElementClosingType _closingType; + // The attribute list is ordered; there is no 'lastAttribute' + // because the list needs to be scanned for dupes before adding + // a new attribute. + XMLAttribute* _rootAttribute; +}; + + +enum Whitespace { + PRESERVE_WHITESPACE, + COLLAPSE_WHITESPACE +}; + + +/** A Document binds together all the functionality. + It can be saved, loaded, and printed to the screen. + All Nodes are connected and allocated to a Document. + If the Document is deleted, all its Nodes are also deleted. +*/ +class TINYXML2_LIB XMLDocument : public XMLNode +{ + friend class XMLElement; + // Gives access to SetError, but over-access for everything else. + // Wishing C++ had "internal" scope. + friend class XMLNode; + friend class XMLText; + friend class XMLComment; + friend class XMLDeclaration; + friend class XMLUnknown; +public: + /// constructor + XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE ); + ~XMLDocument(); + + virtual XMLDocument* ToDocument() { + TIXMLASSERT( this == _document ); + return this; + } + virtual const XMLDocument* ToDocument() const { + TIXMLASSERT( this == _document ); + return this; + } + + /** + Parse an XML file from a character string. + Returns XML_SUCCESS (0) on success, or + an errorID. + + You may optionally pass in the 'nBytes', which is + the number of bytes which will be parsed. If not + specified, TinyXML-2 will assume 'xml' points to a + null terminated string. + */ + XMLError Parse( const char* xml, size_t nBytes=(size_t)(-1) ); + + /** + Load an XML file from disk. + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError LoadFile( const char* filename ); + + /** + Load an XML file from disk. You are responsible + for providing and closing the FILE*. + + NOTE: The file should be opened as binary ("rb") + not text in order for TinyXML-2 to correctly + do newline normalization. + + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError LoadFile( FILE* ); + + /** + Save the XML file to disk. + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError SaveFile( const char* filename, bool compact = false ); + + /** + Save the XML file to disk. You are responsible + for providing and closing the FILE*. + + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError SaveFile( FILE* fp, bool compact = false ); + + bool ProcessEntities() const { + return _processEntities; + } + Whitespace WhitespaceMode() const { + return _whitespaceMode; + } + + /** + Returns true if this document has a leading Byte Order Mark of UTF8. + */ + bool HasBOM() const { + return _writeBOM; + } + /** Sets whether to write the BOM when writing the file. + */ + void SetBOM( bool useBOM ) { + _writeBOM = useBOM; + } + + /** Return the root element of DOM. Equivalent to FirstChildElement(). + To get the first node, use FirstChild(). + */ + XMLElement* RootElement() { + return FirstChildElement(); + } + const XMLElement* RootElement() const { + return FirstChildElement(); + } + + /** Print the Document. If the Printer is not provided, it will + print to stdout. If you provide Printer, this can print to a file: + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Or you can use a printer to print to memory: + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + // printer.CStr() has a const char* to the XML + @endverbatim + */ + void Print( XMLPrinter* streamer=0 ) const; + virtual bool Accept( XMLVisitor* visitor ) const; + + /** + Create a new Element associated with + this Document. The memory for the Element + is managed by the Document. + */ + XMLElement* NewElement( const char* name ); + /** + Create a new Comment associated with + this Document. The memory for the Comment + is managed by the Document. + */ + XMLComment* NewComment( const char* comment ); + /** + Create a new Text associated with + this Document. The memory for the Text + is managed by the Document. + */ + XMLText* NewText( const char* text ); + /** + Create a new Declaration associated with + this Document. The memory for the object + is managed by the Document. + + If the 'text' param is null, the standard + declaration is used.: + @verbatim + <?xml version="1.0" encoding="UTF-8"?> + @endverbatim + */ + XMLDeclaration* NewDeclaration( const char* text=0 ); + /** + Create a new Unknown associated with + this Document. The memory for the object + is managed by the Document. + */ + XMLUnknown* NewUnknown( const char* text ); + + /** + Delete a node associated with this document. + It will be unlinked from the DOM. + */ + void DeleteNode( XMLNode* node ); + + void ClearError() { + SetError(XML_SUCCESS, 0, 0); + } + + /// Return true if there was an error parsing the document. + bool Error() const { + return _errorID != XML_SUCCESS; + } + /// Return the errorID. + XMLError ErrorID() const { + return _errorID; + } + const char* ErrorName() const; + static const char* ErrorIDToName(XMLError errorID); + + /** Returns a "long form" error description. A hopefully helpful + diagnostic with location, line number, and/or additional info. + */ + const char* ErrorStr() const; + + /// A (trivial) utility function that prints the ErrorStr() to stdout. + void PrintError() const; + + /// Return the line where the error occurred, or zero if unknown. + int ErrorLineNum() const + { + return _errorLineNum; + } + + /// Clear the document, resetting it to the initial state. + void Clear(); + + /** + Copies this document to a target document. + The target will be completely cleared before the copy. + If you want to copy a sub-tree, see XMLNode::DeepClone(). + + NOTE: that the 'target' must be non-null. + */ + void DeepCopy(XMLDocument* target) const; + + // internal + char* Identify( char* p, XMLNode** node ); + + // internal + void MarkInUse(XMLNode*); + + virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { + return 0; + } + virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { + return false; + } + +private: + XMLDocument( const XMLDocument& ); // not supported + void operator=( const XMLDocument& ); // not supported + + bool _writeBOM; + bool _processEntities; + XMLError _errorID; + Whitespace _whitespaceMode; + mutable StrPair _errorStr; + int _errorLineNum; + char* _charBuffer; + int _parseCurLineNum; + // Memory tracking does add some overhead. + // However, the code assumes that you don't + // have a bunch of unlinked nodes around. + // Therefore it takes less memory to track + // in the document vs. a linked list in the XMLNode, + // and the performance is the same. + DynArray<XMLNode*, 10> _unlinked; + + MemPoolT< sizeof(XMLElement) > _elementPool; + MemPoolT< sizeof(XMLAttribute) > _attributePool; + MemPoolT< sizeof(XMLText) > _textPool; + MemPoolT< sizeof(XMLComment) > _commentPool; + + static const char* _errorNames[XML_ERROR_COUNT]; + + void Parse(); + + void SetError( XMLError error, int lineNum, const char* format, ... ); + + template<class NodeType, int PoolElementSize> + NodeType* CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool ); +}; + +template<class NodeType, int PoolElementSize> +inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool ) +{ + TIXMLASSERT( sizeof( NodeType ) == PoolElementSize ); + TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() ); + NodeType* returnNode = new (pool.Alloc()) NodeType( this ); + TIXMLASSERT( returnNode ); + returnNode->_memPool = &pool; + + _unlinked.Push(returnNode); + return returnNode; +} + +/** + A XMLHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + <Document> + <Element attributeA = "valueA"> + <Child attributeB = "value1" /> + <Child attributeB = "value2" /> + </Element> + </Document> + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + XMLElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + XMLElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + XMLElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + XMLElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. XMLHandle addresses the verbosity + of such code. A XMLHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + XMLHandle docHandle( &document ); + XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + XMLHandle handleCopy = handle; + @endverbatim + + See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. +*/ +class TINYXML2_LIB XMLHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + XMLHandle( XMLNode* node ) : _node( node ) { + } + /// Create a handle from a node. + XMLHandle( XMLNode& node ) : _node( &node ) { + } + /// Copy constructor + XMLHandle( const XMLHandle& ref ) : _node( ref._node ) { + } + /// Assignment + XMLHandle& operator=( const XMLHandle& ref ) { + _node = ref._node; + return *this; + } + + /// Get the first child of this handle. + XMLHandle FirstChild() { + return XMLHandle( _node ? _node->FirstChild() : 0 ); + } + /// Get the first child element of this handle. + XMLHandle FirstChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 ); + } + /// Get the last child of this handle. + XMLHandle LastChild() { + return XMLHandle( _node ? _node->LastChild() : 0 ); + } + /// Get the last child element of this handle. + XMLHandle LastChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->LastChildElement( name ) : 0 ); + } + /// Get the previous sibling of this handle. + XMLHandle PreviousSibling() { + return XMLHandle( _node ? _node->PreviousSibling() : 0 ); + } + /// Get the previous sibling element of this handle. + XMLHandle PreviousSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); + } + /// Get the next sibling of this handle. + XMLHandle NextSibling() { + return XMLHandle( _node ? _node->NextSibling() : 0 ); + } + /// Get the next sibling element of this handle. + XMLHandle NextSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 ); + } + + /// Safe cast to XMLNode. This can return null. + XMLNode* ToNode() { + return _node; + } + /// Safe cast to XMLElement. This can return null. + XMLElement* ToElement() { + return ( _node ? _node->ToElement() : 0 ); + } + /// Safe cast to XMLText. This can return null. + XMLText* ToText() { + return ( _node ? _node->ToText() : 0 ); + } + /// Safe cast to XMLUnknown. This can return null. + XMLUnknown* ToUnknown() { + return ( _node ? _node->ToUnknown() : 0 ); + } + /// Safe cast to XMLDeclaration. This can return null. + XMLDeclaration* ToDeclaration() { + return ( _node ? _node->ToDeclaration() : 0 ); + } + +private: + XMLNode* _node; +}; + + +/** + A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the + same in all regards, except for the 'const' qualifiers. See XMLHandle for API. +*/ +class TINYXML2_LIB XMLConstHandle +{ +public: + XMLConstHandle( const XMLNode* node ) : _node( node ) { + } + XMLConstHandle( const XMLNode& node ) : _node( &node ) { + } + XMLConstHandle( const XMLConstHandle& ref ) : _node( ref._node ) { + } + + XMLConstHandle& operator=( const XMLConstHandle& ref ) { + _node = ref._node; + return *this; + } + + const XMLConstHandle FirstChild() const { + return XMLConstHandle( _node ? _node->FirstChild() : 0 ); + } + const XMLConstHandle FirstChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 ); + } + const XMLConstHandle LastChild() const { + return XMLConstHandle( _node ? _node->LastChild() : 0 ); + } + const XMLConstHandle LastChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 ); + } + const XMLConstHandle PreviousSibling() const { + return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); + } + const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); + } + const XMLConstHandle NextSibling() const { + return XMLConstHandle( _node ? _node->NextSibling() : 0 ); + } + const XMLConstHandle NextSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 ); + } + + + const XMLNode* ToNode() const { + return _node; + } + const XMLElement* ToElement() const { + return ( _node ? _node->ToElement() : 0 ); + } + const XMLText* ToText() const { + return ( _node ? _node->ToText() : 0 ); + } + const XMLUnknown* ToUnknown() const { + return ( _node ? _node->ToUnknown() : 0 ); + } + const XMLDeclaration* ToDeclaration() const { + return ( _node ? _node->ToDeclaration() : 0 ); + } + +private: + const XMLNode* _node; +}; + + +/** + Printing functionality. The XMLPrinter gives you more + options than the XMLDocument::Print() method. + + It can: + -# Print to memory. + -# Print to a file you provide. + -# Print XML without a XMLDocument. + + Print to Memory + + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + SomeFunction( printer.CStr() ); + @endverbatim + + Print to a File + + You provide the file pointer. + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Print without a XMLDocument + + When loading, an XML parser is very useful. However, sometimes + when saving, it just gets in the way. The code is often set up + for streaming, and constructing the DOM is just overhead. + + The Printer supports the streaming case. The following code + prints out a trivially simple XML file without ever creating + an XML document. + + @verbatim + XMLPrinter printer( fp ); + printer.OpenElement( "foo" ); + printer.PushAttribute( "foo", "bar" ); + printer.CloseElement(); + @endverbatim +*/ +class TINYXML2_LIB XMLPrinter : public XMLVisitor +{ +public: + /** Construct the printer. If the FILE* is specified, + this will print to the FILE. Else it will print + to memory, and the result is available in CStr(). + If 'compact' is set to true, then output is created + with only required whitespace and newlines. + */ + XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 ); + virtual ~XMLPrinter() {} + + /** If streaming, write the BOM and declaration. */ + void PushHeader( bool writeBOM, bool writeDeclaration ); + /** If streaming, start writing an element. + The element must be closed with CloseElement() + */ + void OpenElement( const char* name, bool compactMode=false ); + /// If streaming, add an attribute to an open element. + void PushAttribute( const char* name, const char* value ); + void PushAttribute( const char* name, int value ); + void PushAttribute( const char* name, unsigned value ); + void PushAttribute(const char* name, int64_t value); + void PushAttribute( const char* name, bool value ); + void PushAttribute( const char* name, double value ); + /// If streaming, close the Element. + virtual void CloseElement( bool compactMode=false ); + + /// Add a text node. + void PushText( const char* text, bool cdata=false ); + /// Add a text node from an integer. + void PushText( int value ); + /// Add a text node from an unsigned. + void PushText( unsigned value ); + /// Add a text node from an unsigned. + void PushText(int64_t value); + /// Add a text node from a bool. + void PushText( bool value ); + /// Add a text node from a float. + void PushText( float value ); + /// Add a text node from a double. + void PushText( double value ); + + /// Add a comment + void PushComment( const char* comment ); + + void PushDeclaration( const char* value ); + void PushUnknown( const char* value ); + + virtual bool VisitEnter( const XMLDocument& /*doc*/ ); + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ); + virtual bool VisitExit( const XMLElement& element ); + + virtual bool Visit( const XMLText& text ); + virtual bool Visit( const XMLComment& comment ); + virtual bool Visit( const XMLDeclaration& declaration ); + virtual bool Visit( const XMLUnknown& unknown ); + + /** + If in print to memory mode, return a pointer to + the XML file in memory. + */ + const char* CStr() const { + return _buffer.Mem(); + } + /** + If in print to memory mode, return the size + of the XML file in memory. (Note the size returned + includes the terminating null.) + */ + int CStrSize() const { + return _buffer.Size(); + } + /** + If in print to memory mode, reset the buffer to the + beginning. + */ + void ClearBuffer() { + _buffer.Clear(); + _buffer.Push(0); + _firstElement = true; + } + +protected: + virtual bool CompactMode( const XMLElement& ) { return _compactMode; } + + /** Prints out the space before an element. You may override to change + the space and tabs used. A PrintSpace() override should call Print(). + */ + virtual void PrintSpace( int depth ); + void Print( const char* format, ... ); + void Write( const char* data, size_t size ); + inline void Write( const char* data ) { Write( data, strlen( data ) ); } + void Putc( char ch ); + + void SealElementIfJustOpened(); + bool _elementJustOpened; + DynArray< const char*, 10 > _stack; + +private: + void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. + + bool _firstElement; + FILE* _fp; + int _depth; + int _textDepth; + bool _processEntities; + bool _compactMode; + + enum { + ENTITY_RANGE = 64, + BUF_SIZE = 200 + }; + bool _entityFlag[ENTITY_RANGE]; + bool _restrictedEntityFlag[ENTITY_RANGE]; + + DynArray< char, 20 > _buffer; + + // Prohibit cloning, intentionally not implemented + XMLPrinter( const XMLPrinter& ); + XMLPrinter& operator=( const XMLPrinter& ); +}; + + +} // tinyxml2 +} // namespace External +} // namespace Aws + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif // TINYXML2_INCLUDED
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/HttpClient.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/HttpClient.h new file mode 100644 index 0000000000..4c292064d7 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/HttpClient.h @@ -0,0 +1,81 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <memory> +#include <atomic> +#include <mutex> +#include <condition_variable> + +namespace Aws +{ + namespace Utils + { + namespace RateLimits + { + class RateLimiterInterface; + } // namespace RateLimits + } // namespace Utils + + namespace Http + { + class HttpRequest; + class HttpResponse; + + /** + * Abstract HttpClient. All it does is make HttpRequests and return their response. + */ + class AWS_CORE_API HttpClient + { + public: + HttpClient(); + virtual ~HttpClient() {} + + /** + * Takes an http request, makes it, and returns the newly allocated HttpResponse. + */ + virtual std::shared_ptr<HttpResponse> MakeRequest(const std::shared_ptr<HttpRequest>& request, + Aws::Utils::RateLimits::RateLimiterInterface* readLimiter = nullptr, + Aws::Utils::RateLimits::RateLimiterInterface* writeLimiter = nullptr) const = 0; + + /** + * If yes, the http client supports transfer-encoding:chunked. + */ + virtual bool SupportsChunkedTransferEncoding() const { return true; } + + /** + * Stops all requests in progress and prevents any others from initiating. + */ + void DisableRequestProcessing(); + /** + * Enables/ReEnables request processing. + */ + void EnableRequestProcessing(); + /** + * Returns true if request processing is enabled. + */ + bool IsRequestProcessingEnabled() const; + /** + * Sleeps current thread for sleepTime. + */ + void RetryRequestSleep(std::chrono::milliseconds sleepTime); + + bool ContinueRequest(const Aws::Http::HttpRequest&) const; + + private: + + std::atomic< bool > m_disableRequestProcessing; + + std::mutex m_requestProcessingSignalLock; + std::condition_variable m_requestProcessingSignal; + }; + + } // namespace Http +} // namespace Aws + + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/HttpClientFactory.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/HttpClientFactory.h new file mode 100644 index 0000000000..a82a773c04 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/HttpClientFactory.h @@ -0,0 +1,65 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/http/HttpTypes.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> + +namespace Aws +{ + namespace Client + { + struct ClientConfiguration; + } // namespace Client + namespace Http + { + class URI; + class HttpClient; + class HttpRequest; + + /** + * Interface and default implementation of client for Http stack + */ + class AWS_CORE_API HttpClientFactory + { + public: + virtual ~HttpClientFactory() {} + + /** + * Creates a shared_ptr of HttpClient with the relevant settings from clientConfiguration + */ + virtual std::shared_ptr<HttpClient> CreateHttpClient(const Aws::Client::ClientConfiguration& clientConfiguration) const = 0; + /** + * Creates a shared_ptr of HttpRequest with uri, method, and closure for how to create a response stream. + */ + virtual std::shared_ptr<HttpRequest> CreateHttpRequest(const Aws::String& uri, HttpMethod method, const Aws::IOStreamFactory& streamFactory) const = 0; + /** + * Creates a shared_ptr of HttpRequest with uri, method, and closure for how to create a response stream. + */ + virtual std::shared_ptr<HttpRequest> CreateHttpRequest(const URI& uri, HttpMethod method, const Aws::IOStreamFactory& streamFactory) const = 0; + + virtual void InitStaticState() {} + virtual void CleanupStaticState() {} + }; + + /** + * libCurl infects everything with its global state. If it is being used then we automatically initialize and clean it up. + * If this is a problem for you, set this to false. If you manually initialize libcurl please add the option CURL_GLOBAL_ALL to your init call. + */ + AWS_CORE_API void SetInitCleanupCurlFlag(bool initCleanupFlag); + AWS_CORE_API void SetInstallSigPipeHandlerFlag(bool installHandler); + AWS_CORE_API void InitHttp(); + AWS_CORE_API void CleanupHttp(); + AWS_CORE_API void SetHttpClientFactory(const std::shared_ptr<HttpClientFactory>& factory); + AWS_CORE_API std::shared_ptr<HttpClient> CreateHttpClient(const Aws::Client::ClientConfiguration& clientConfiguration); + AWS_CORE_API std::shared_ptr<HttpRequest> CreateHttpRequest(const Aws::String& uri, HttpMethod method, const Aws::IOStreamFactory& streamFactory); + AWS_CORE_API std::shared_ptr<HttpRequest> CreateHttpRequest(const URI& uri, HttpMethod method, const Aws::IOStreamFactory& streamFactory); + + } // namespace Http +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/HttpRequest.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/HttpRequest.h new file mode 100644 index 0000000000..ab71a3a29b --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/HttpRequest.h @@ -0,0 +1,542 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/http/URI.h> +#include <aws/core/http/HttpTypes.h> +#include <aws/core/utils/memory/AWSMemory.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/utils/stream/ResponseStream.h> +#include <aws/core/monitoring/HttpClientMetrics.h> +#include <memory> +#include <functional> + +namespace Aws +{ + namespace Http + { + extern AWS_CORE_API const char DATE_HEADER[]; + extern AWS_CORE_API const char AWS_DATE_HEADER[]; + extern AWS_CORE_API const char AWS_SECURITY_TOKEN[]; + extern AWS_CORE_API const char ACCEPT_HEADER[]; + extern AWS_CORE_API const char ACCEPT_CHAR_SET_HEADER[]; + extern AWS_CORE_API const char ACCEPT_ENCODING_HEADER[]; + extern AWS_CORE_API const char AUTHORIZATION_HEADER[]; + extern AWS_CORE_API const char AWS_AUTHORIZATION_HEADER[]; + extern AWS_CORE_API const char COOKIE_HEADER[]; + extern AWS_CORE_API const char CONTENT_LENGTH_HEADER[]; + extern AWS_CORE_API const char CONTENT_TYPE_HEADER[]; + extern AWS_CORE_API const char TRANSFER_ENCODING_HEADER[]; + extern AWS_CORE_API const char USER_AGENT_HEADER[]; + extern AWS_CORE_API const char VIA_HEADER[]; + extern AWS_CORE_API const char HOST_HEADER[]; + extern AWS_CORE_API const char AMZ_TARGET_HEADER[]; + extern AWS_CORE_API const char X_AMZ_EXPIRES_HEADER[]; + extern AWS_CORE_API const char CONTENT_MD5_HEADER[]; + extern AWS_CORE_API const char API_VERSION_HEADER[]; + extern AWS_CORE_API const char SDK_INVOCATION_ID_HEADER[]; + extern AWS_CORE_API const char SDK_REQUEST_HEADER[]; + extern AWS_CORE_API const char CHUNKED_VALUE[]; + + class HttpRequest; + class HttpResponse; + + /** + * closure type for receiving notifications that data has been received. + */ + typedef std::function<void(const HttpRequest*, HttpResponse*, long long)> DataReceivedEventHandler; + /** + * closure type for receiving notifications that data has been sent. + */ + typedef std::function<void(const HttpRequest*, long long)> DataSentEventHandler; + /** + * Closure type for handling whether or not a request should be canceled. + */ + typedef std::function<bool(const HttpRequest*)> ContinueRequestHandler; + + /** + * Abstract class for representing an HttpRequest. + */ + class AWS_CORE_API HttpRequest + { + public: + /** + * Initializes an HttpRequest object with uri and http method. + */ + HttpRequest(const URI& uri, HttpMethod method) : + m_uri(uri), m_method(method), m_isEvenStreamRequest(false) + {} + + virtual ~HttpRequest() {} + + /** + * Get All headers for this request. + */ + virtual HeaderValueCollection GetHeaders() const = 0; + /** + * Get the value for a Header based on its name. (in default StandardHttpRequest implementation, an empty string will be returned if headerName doesn't exist) + */ + virtual const Aws::String& GetHeaderValue(const char* headerName) const = 0; + /** + * Add a header pair + */ + virtual void SetHeaderValue(const char* headerName, const Aws::String& headerValue) = 0; + /** + * Creates a shared_ptr of HttpRequest with uri, method, and closure for how to create a response stream. + */ + virtual void SetHeaderValue(const Aws::String& headerName, const Aws::String& headerValue) = 0; + /** + * Deletes a header from the request by name. + */ + virtual void DeleteHeader(const char* headerName) = 0; + /** + * Adds a content body stream to the request. This stream will be used to send the body to the endpoint. + */ + virtual void AddContentBody(const std::shared_ptr<Aws::IOStream>& strContent) = 0; + /** + * Gets the content body stream that will be used for this request. + */ + virtual const std::shared_ptr<Aws::IOStream>& GetContentBody() const = 0; + /** + * Returns true if a header exists in the request with name + */ + virtual bool HasHeader(const char* name) const = 0; + /** + * Get size in bytes of the request when as it will be going accross the wire. + */ + virtual int64_t GetSize() const = 0; + /** + * Gets the factory for creating the stream that will be used in the http response. + */ + virtual const Aws::IOStreamFactory& GetResponseStreamFactory() const = 0; + /** + * Sets the factory for creating the stream that will be used in the http response. + */ + virtual void SetResponseStreamFactory(const Aws::IOStreamFactory& factory) = 0; + /** + * Gets underlying URI object with mutation access. + */ + inline URI& GetUri() + { + return m_uri; + } + /** + * Gets the underlying URI object. + */ + const URI& GetUri() const { return m_uri; } + /** + * Converts the URI into a string and returns it. If includeQueryString is set to true, the query string + * will be included in the returned value. + */ + inline Aws::String GetURIString(bool includeQueryString = true) const + { + return m_uri.GetURIString(includeQueryString); + } + /** + * Get the http method for this request. + */ + inline HttpMethod GetMethod() const + { + return m_method; + } + /** + * Gets the query string from the URI on this request. + */ + inline const Aws::String& GetQueryString() const + { + return m_uri.GetQueryString(); + } + /** + * Normalizes the URI for use with signing. + */ + inline void CanonicalizeRequest() + { + m_uri.CanonicalizeQueryString(); + } + /** + * Gets the query string for the underlying URI as a key value mapping + */ + inline QueryStringParameterCollection GetQueryStringParameters() const + { + return m_uri.GetQueryStringParameters(); + } + /** + * Adds a query string parameter to the underlying URI by key and value. + */ + inline void AddQueryStringParameter(const char* key, const Aws::String& value) + { + m_uri.AddQueryStringParameter(key, value); + } + + inline bool HasDate() const + { + return HasHeader(DATE_HEADER); + } + /** + * Gets date header. + */ + inline const Aws::String& GetDate() const + { + return GetHeaderValue(DATE_HEADER); + } + /** + * Gets date header. + */ + inline void SetDate(const Aws::String& value) + { + SetHeaderValue(DATE_HEADER, value); + } + + inline bool HasAccept() const + { + return HasHeader(ACCEPT_HEADER); + } + /** + * Gets accept header. + */ + inline const Aws::String& GetAccept() const + { + return GetHeaderValue(ACCEPT_HEADER); + } + /** + * Gets accept header. + */ + inline void SetAccept(const Aws::String& value) + { + SetHeaderValue(ACCEPT_HEADER, value); + } + + inline bool HasAcceptCharSet() const + { + return HasHeader(ACCEPT_CHAR_SET_HEADER); + } + /** + * Gets Accept CharSet header. + */ + inline const Aws::String& GetAcceptCharSet() const + { + return GetHeaderValue(ACCEPT_CHAR_SET_HEADER); + } + /** + * Sets Accept CharSet header. + */ + inline void SetAcceptCharSet(const Aws::String& value) + { + SetHeaderValue(ACCEPT_CHAR_SET_HEADER, value); + } + + inline bool HasAcceptEncoding() const + { + return HasHeader(ACCEPT_ENCODING_HEADER); + } + /** + * Gets accept encoding header. + */ + inline const Aws::String& GetAcceptEncoding() const + { + return GetHeaderValue(ACCEPT_ENCODING_HEADER); + } + /** + * Sets accept encoding header. + */ + inline void SetAcceptEncoding(const Aws::String& value) + { + SetHeaderValue(ACCEPT_ENCODING_HEADER, value); + } + + inline bool HasAuthorization() const + { + return HasHeader(AUTHORIZATION_HEADER); + } + /** + * Gets authorization encoding header. + */ + inline const Aws::String& GetAuthorization() const + { + return GetHeaderValue(AUTHORIZATION_HEADER); + } + /** + * Set authorization header. + */ + inline void SetAuthorization(const Aws::String& value) + { + SetHeaderValue(AUTHORIZATION_HEADER, value); + } + + inline bool HasAwsAuthorization() const + { + return HasHeader(AWS_AUTHORIZATION_HEADER); + } + /** + * Gets aws authorization header. + */ + inline const Aws::String& GetAwsAuthorization() const + { + return GetHeaderValue(AWS_AUTHORIZATION_HEADER); + } + /** + * Sets aws authorization header. + */ + inline void SetAwsAuthorization(const Aws::String& value) + { + SetHeaderValue(AWS_AUTHORIZATION_HEADER, value); + } + + inline bool HasAwsSessionToken() const + { + return HasHeader(AWS_SECURITY_TOKEN); + } + /** + * Gets session token header. + */ + inline const Aws::String& GetAwsSessionToken() const + { + return GetHeaderValue(AWS_SECURITY_TOKEN); + } + /** + * Sets session token header. + */ + inline void SetAwsSessionToken(const Aws::String& value) + { + SetHeaderValue(AWS_SECURITY_TOKEN, value); + } + + inline bool HasCookie() const + { + return HasHeader(COOKIE_HEADER); + } + /** + * Gets cookie header. + */ + inline const Aws::String& GetCookie() const + { + return GetHeaderValue(COOKIE_HEADER); + } + /** + * Sets cookie header. + */ + inline void SetCookie(const Aws::String& value) + { + SetHeaderValue(COOKIE_HEADER, value); + } + + inline bool HasContentLength() const + { + return HasHeader(CONTENT_LENGTH_HEADER); + } + /** + * Gets content-length header. + */ + inline const Aws::String& GetContentLength() const + { + return GetHeaderValue(CONTENT_LENGTH_HEADER); + } + /** + * Sets content-length header. + */ + inline void SetContentLength(const Aws::String& value) + { + SetHeaderValue(CONTENT_LENGTH_HEADER, value); + } + + inline bool HasContentType() const + { + return HasHeader(CONTENT_TYPE_HEADER); + } + /** + * Gets content-type header. + */ + inline const Aws::String& GetContentType() const + { + return GetHeaderValue(CONTENT_TYPE_HEADER); + } + /** + * sets content-type header. + */ + inline void SetContentType(const Aws::String& value) + { + SetHeaderValue(CONTENT_TYPE_HEADER, value); + } + + inline bool HasTransferEncoding() const + { + return HasHeader(TRANSFER_ENCODING_HEADER); + } + /** + * Gets transfer-encoding header. + */ + inline const Aws::String& GetTransferEncoding() const + { + return GetHeaderValue(TRANSFER_ENCODING_HEADER); + } + /** + * Sets transfer-encoding header. + */ + inline void SetTransferEncoding(const Aws::String& value) + { + SetHeaderValue(TRANSFER_ENCODING_HEADER, value); + } + + inline bool HasUserAgent() const + { + return HasHeader(USER_AGENT_HEADER); + } + /** + * Gets User Agent header. + */ + inline const Aws::String& GetUserAgent() const + { + return GetHeaderValue(USER_AGENT_HEADER); + } + /** + * Sets User Agent header. + */ + inline void SetUserAgent(const Aws::String& value) + { + SetHeaderValue(USER_AGENT_HEADER, value); + } + + inline bool HasVia() const + { + return HasHeader(VIA_HEADER); + } + /** + * Gets via header header. + */ + inline const Aws::String& GetVia() const + { + return GetHeaderValue(VIA_HEADER); + } + /** + * Sets via header. + */ + inline void SetVia(const Aws::String& value) + { + SetHeaderValue(VIA_HEADER, value); + } + + /** + * Has Api version header x-amz-api-version + */ + inline bool HasApiVersion() const + { + return HasHeader(API_VERSION_HEADER); + } + + /** + * Gets Api version header x-amz-api-version. + */ + inline const Aws::String& GetApiVersion() const + { + return GetHeaderValue(API_VERSION_HEADER); + } + /** + * Sets Api version header x-amz-api-version. + */ + inline void SetApiVersion(const Aws::String& value) + { + SetHeaderValue(API_VERSION_HEADER, value); + } + + /** + * Sets the closure for receiving events when data is received from the server. + */ + inline void SetDataReceivedEventHandler(const DataReceivedEventHandler& dataReceivedEventHandler) { m_onDataReceived = dataReceivedEventHandler; } + /** + * Sets the closure for receiving events when data is received from the server. + */ + inline void SetDataReceivedEventHandler(DataReceivedEventHandler&& dataReceivedEventHandler) { m_onDataReceived = std::move(dataReceivedEventHandler); } + /** + * Sets the closure for receiving events when data is sent to the server. + */ + inline void SetDataSentEventHandler(const DataSentEventHandler& dataSentEventHandler) { m_onDataSent = dataSentEventHandler; } + /** + * Sets the closure for receiving events when data is sent to the server. + */ + inline void SetDataSentEventHandler(DataSentEventHandler&& dataSentEventHandler) { m_onDataSent = std::move(dataSentEventHandler); } + /** + * Sets the closure for handling whether or not to cancel a request. + */ + inline void SetContinueRequestHandle(const ContinueRequestHandler& continueRequestHandler) { m_continueRequest = continueRequestHandler; } + /** + * Sets the closure for handling whether or not to cancel a request. + */ + inline void SetContinueRequestHandle(ContinueRequestHandler&& continueRequestHandler) { m_continueRequest = std::move(continueRequestHandler); } + + /** + * Gets the closure for receiving events when data is received from the server. + */ + inline const DataReceivedEventHandler& GetDataReceivedEventHandler() const { return m_onDataReceived; } + /** + * Gets the closure for receiving events when data is sent to the server. + */ + inline const DataSentEventHandler& GetDataSentEventHandler() const { return m_onDataSent; } + + inline const ContinueRequestHandler& GetContinueRequestHandler() const { return m_continueRequest; } + + /** + * Gets the AWS Access Key if this HttpRequest is signed with Aws Access Key + */ + inline const Aws::String& GetSigningAccessKey() const { return m_signingAccessKey; } + /** + * Sets the Aws Access Key if this HttpRequest is signed with Aws Access Key + */ + inline void SetSigningAccessKey(const Aws::String& accessKey) { m_signingAccessKey = accessKey; } + + /** + * Gets the signing region if this request is signed. + */ + inline const Aws::String& GetSigningRegion() const { return m_signingRegion; } + /** + * Sets the signing region if this request is signed. + */ + inline void SetSigningRegion(const Aws::String& region) { m_signingRegion = region; } + + /** + * Add a request metric + * @param key, HttpClientMetricsKey defined in HttpClientMetrics.cpp + * @param value, the corresponding value of this key measured during http request. + */ + virtual void AddRequestMetric(const Aws::String& key, int64_t value) { m_httpRequestMetrics.emplace(key, value); } + + /** + * Sets the request metrics + */ + virtual void SetRequestMetrics(const Aws::Monitoring::HttpClientMetricsCollection& collection) { m_httpRequestMetrics = collection; } + + /** + * Gets the request metrics + */ + virtual const Aws::Monitoring::HttpClientMetricsCollection& GetRequestMetrics() const { return m_httpRequestMetrics; } + + /** + * Returns the IP address of the remote host the request was made out to. + * This value is populated after the request is made and when the HTTP client supports retrieving such + * information. + * If the information is not available, an empty string is returned. + */ + Aws::String GetResolvedRemoteHost() const { return m_resolvedRemoteHost; } + void SetResolvedRemoteHost(const Aws::String& ip) { m_resolvedRemoteHost = ip; } + + bool IsEventStreamRequest() { return m_isEvenStreamRequest; } + void SetEventStreamRequest(bool eventStreamRequest) { m_isEvenStreamRequest = eventStreamRequest; } + private: + URI m_uri; + HttpMethod m_method; + bool m_isEvenStreamRequest; + DataReceivedEventHandler m_onDataReceived; + DataSentEventHandler m_onDataSent; + ContinueRequestHandler m_continueRequest; + Aws::String m_signingRegion; + Aws::String m_signingAccessKey; + Aws::String m_resolvedRemoteHost; + Aws::Monitoring::HttpClientMetricsCollection m_httpRequestMetrics; + }; + + } // namespace Http +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/HttpResponse.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/HttpResponse.h new file mode 100644 index 0000000000..1db30d1730 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/HttpResponse.h @@ -0,0 +1,219 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/http/HttpRequest.h> +#include <aws/core/http/HttpTypes.h> +#include <aws/core/utils/memory/AWSMemory.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/client/CoreErrors.h> + +namespace Aws +{ + namespace Utils + { + namespace Stream + { + class ResponseStream; + } + } + namespace Http + { + /** + * Enum of Http response Codes. The integer values of the response codes correspond to the values in the RFC. + */ + enum class HttpResponseCode + { + REQUEST_NOT_MADE = -1, + CONTINUE = 100, + SWITCHING_PROTOCOLS = 101, + PROCESSING = 102, + OK = 200, + CREATED = 201, + ACCEPTED = 202, + NON_AUTHORITATIVE_INFORMATION = 203, + NO_CONTENT = 204, + RESET_CONTENT = 205, + PARTIAL_CONTENT = 206, + MULTI_STATUS = 207, + ALREADY_REPORTED = 208, + IM_USED = 226, + MULTIPLE_CHOICES = 300, + MOVED_PERMANENTLY = 301, + FOUND = 302, + SEE_OTHER = 303, + NOT_MODIFIED = 304, + USE_PROXY = 305, + SWITCH_PROXY = 306, + TEMPORARY_REDIRECT = 307, + PERMANENT_REDIRECT = 308, + BAD_REQUEST = 400, + UNAUTHORIZED = 401, + PAYMENT_REQUIRED = 402, + FORBIDDEN = 403, + NOT_FOUND = 404, + METHOD_NOT_ALLOWED = 405, + NOT_ACCEPTABLE = 406, + PROXY_AUTHENTICATION_REQUIRED = 407, + REQUEST_TIMEOUT = 408, + CONFLICT = 409, + GONE = 410, + LENGTH_REQUIRED = 411, + PRECONDITION_FAILED = 412, + REQUEST_ENTITY_TOO_LARGE = 413, + REQUEST_URI_TOO_LONG = 414, + UNSUPPORTED_MEDIA_TYPE = 415, + REQUESTED_RANGE_NOT_SATISFIABLE = 416, + EXPECTATION_FAILED = 417, + IM_A_TEAPOT = 418, + AUTHENTICATION_TIMEOUT = 419, + METHOD_FAILURE = 420, + UNPROC_ENTITY = 422, + LOCKED = 423, + FAILED_DEPENDENCY = 424, + UPGRADE_REQUIRED = 426, + PRECONDITION_REQUIRED = 427, + TOO_MANY_REQUESTS = 429, + REQUEST_HEADER_FIELDS_TOO_LARGE = 431, + LOGIN_TIMEOUT = 440, + NO_RESPONSE = 444, + RETRY_WITH = 449, + BLOCKED = 450, + REDIRECT = 451, + REQUEST_HEADER_TOO_LARGE = 494, + CERT_ERROR = 495, + NO_CERT = 496, + HTTP_TO_HTTPS = 497, + CLIENT_CLOSED_TO_REQUEST = 499, + INTERNAL_SERVER_ERROR = 500, + NOT_IMPLEMENTED = 501, + BAD_GATEWAY = 502, + SERVICE_UNAVAILABLE = 503, + GATEWAY_TIMEOUT = 504, + HTTP_VERSION_NOT_SUPPORTED = 505, + VARIANT_ALSO_NEGOTIATES = 506, + INSUFFICIENT_STORAGE = 507, + LOOP_DETECTED = 508, + BANDWIDTH_LIMIT_EXCEEDED = 509, + NOT_EXTENDED = 510, + NETWORK_AUTHENTICATION_REQUIRED = 511, + NETWORK_READ_TIMEOUT = 598, + NETWORK_CONNECT_TIMEOUT = 599 + }; + + inline bool IsRetryableHttpResponseCode(HttpResponseCode responseCode) + { + switch (responseCode) + { + case HttpResponseCode::INTERNAL_SERVER_ERROR: + case HttpResponseCode::SERVICE_UNAVAILABLE: + case HttpResponseCode::TOO_MANY_REQUESTS: + case HttpResponseCode::BANDWIDTH_LIMIT_EXCEEDED: + case HttpResponseCode::REQUEST_TIMEOUT: + case HttpResponseCode::AUTHENTICATION_TIMEOUT: + case HttpResponseCode::LOGIN_TIMEOUT: + case HttpResponseCode::GATEWAY_TIMEOUT: + case HttpResponseCode::NETWORK_READ_TIMEOUT: + case HttpResponseCode::NETWORK_CONNECT_TIMEOUT: + return true; + default: + return false; + } + } + + /** + * Abstract class for representing an Http Response. + */ + class AWS_CORE_API HttpResponse + { + public: + /** + * Initializes an http response with the originalRequest and the response code. + */ + HttpResponse(const std::shared_ptr<const HttpRequest>& originatingRequest) : + m_httpRequest(originatingRequest), + m_responseCode(HttpResponseCode::REQUEST_NOT_MADE), + m_hasClientError(false) + {} + + virtual ~HttpResponse() = default; + + /** + * Gets the request that originated this response + */ + virtual inline const HttpRequest& GetOriginatingRequest() const { return *m_httpRequest; } + + /** + * Sets the request that originated this response + */ + virtual inline void SetOriginatingRequest(const std::shared_ptr<const HttpRequest>& httpRequest) { m_httpRequest = httpRequest; } + + /** + * Get the headers from this response + */ + virtual HeaderValueCollection GetHeaders() const = 0; + /** + * Returns true if the response contains a header by headerName + */ + virtual bool HasHeader(const char* headerName) const = 0; + /** + * Returns the value for a header at headerName if it exists. + */ + virtual const Aws::String& GetHeader(const Aws::String& headerName) const = 0; + /** + * Gets response code for this http response. + */ + virtual inline HttpResponseCode GetResponseCode() const { return m_responseCode; } + /** + * Sets the response code for this http response. + */ + virtual inline void SetResponseCode(HttpResponseCode httpResponseCode) { m_responseCode = httpResponseCode; } + /** + * Gets the content-type of the response body + */ + virtual const Aws::String& GetContentType() const { return GetHeader(Http::CONTENT_TYPE_HEADER); } + /** + * Gets the response body of the response. + */ + virtual Aws::IOStream& GetResponseBody() const = 0; + /** + * Gives full control of the memory of the ResponseBody over to the caller. At this point, it is the caller's + * responsibility to clean up this object. + */ + virtual Utils::Stream::ResponseStream&& SwapResponseStreamOwnership() = 0; + /** + * Adds a header to the http response object. + */ + virtual void AddHeader(const Aws::String&, const Aws::String&) = 0; + /** + * Sets the content type header on the http response object. + */ + virtual void SetContentType(const Aws::String& contentType) { AddHeader("content-type", contentType); } + + inline bool HasClientError() const { return m_hasClientError; } + inline void SetClientErrorType(Aws::Client::CoreErrors errorType) {m_hasClientError = true; m_clientErrorType = errorType;} + inline Aws::Client::CoreErrors GetClientErrorType() { return m_clientErrorType; } + + inline const Aws::String &GetClientErrorMessage() const { return m_clientErrorMessage; } + inline void SetClientErrorMessage(const Aws::String &error) { m_clientErrorMessage = error; } + + private: + HttpResponse(const HttpResponse&); + HttpResponse& operator = (const HttpResponse&); + + std::shared_ptr<const HttpRequest> m_httpRequest; + HttpResponseCode m_responseCode; + // Error generated by http client, SDK or users, indicating non service error during http request + bool m_hasClientError; + Aws::Client::CoreErrors m_clientErrorType; + Aws::String m_clientErrorMessage; + }; + + } // namespace Http +} // namespace Aws + + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/HttpTypes.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/HttpTypes.h new file mode 100644 index 0000000000..b8c993294a --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/HttpTypes.h @@ -0,0 +1,57 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSList.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/memory/stl/AWSMap.h> + +#include <memory> + +namespace Aws +{ + namespace Http + { + /** + * Models Http methods. + */ + enum class HttpMethod + { + HTTP_GET, + HTTP_POST, + HTTP_DELETE, + HTTP_PUT, + HTTP_HEAD, + HTTP_PATCH + }; + + /** + * Possible default http factory vended http client implementations. + */ + enum class TransferLibType + { + DEFAULT_CLIENT = 0, + CURL_CLIENT, + WIN_INET_CLIENT, + WIN_HTTP_CLIENT + }; + + namespace HttpMethodMapper + { + /** + * Gets the string value of an httpMethod. + */ + AWS_CORE_API const char* GetNameForHttpMethod(HttpMethod httpMethod); + } // namespace HttpMethodMapper + + typedef std::pair<Aws::String, Aws::String> HeaderValuePair; + typedef Aws::Map<Aws::String, Aws::String> HeaderValueCollection; + + } // namespace Http +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/Scheme.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/Scheme.h new file mode 100644 index 0000000000..a0ec88ad16 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/Scheme.h @@ -0,0 +1,38 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ + namespace Http + { + /** + * Enum representing URI scheme. + */ + enum class Scheme + { + HTTP, + HTTPS + }; + + namespace SchemeMapper + { + /** + * Converts a Scheme instance to a String. + */ + AWS_CORE_API const char* ToString(Scheme scheme); + /** + * Converts a string instance to a Scheme. Defaults to https. + */ + AWS_CORE_API Scheme FromString(const char* name); + } // namespace SchemeMapper + } // namespace Http +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/URI.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/URI.h new file mode 100644 index 0000000000..d72e96b863 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/URI.h @@ -0,0 +1,171 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/http/Scheme.h> +#include <aws/core/utils/memory/stl/AWSMap.h> +#include <aws/core/utils/memory/stl/AWSString.h> + +#include <stdint.h> + +namespace Aws +{ + namespace Http + { + extern AWS_CORE_API const char* SEPARATOR; + static const uint16_t HTTP_DEFAULT_PORT = 80; + static const uint16_t HTTPS_DEFAULT_PORT = 443; + + //per https://tools.ietf.org/html/rfc3986#section-3.4 there is nothing preventing servers from allowing + //multiple values for the same key. So use a multimap instead of a map. + typedef Aws::MultiMap<Aws::String, Aws::String> QueryStringParameterCollection; + + /** + * class modeling universal resource identifier, but implemented for http + */ + class AWS_CORE_API URI + { + public: + /** + * Defaults to http and port 80 + */ + URI(); + /** + * Parses string and sets uri fields + */ + URI(const Aws::String&); + /** + * Parses string and sets uri fields + */ + URI(const char*); + + URI& operator = (const Aws::String&); + URI& operator = (const char*); + + bool operator == (const URI&) const; + bool operator == (const Aws::String&) const; + bool operator == (const char*) const; + bool operator != (const URI&) const; + bool operator != (const Aws::String&) const; + bool operator != (const char*) const; + + /** + * scheme or protocol e.g. http, https, ftp + */ + inline Scheme GetScheme() const { return m_scheme; } + + /** + * Sets scheme, if the port is incompatible with this scheme, the port will automatically be set as well. + */ + void SetScheme(Scheme value); + + /** + * Gets the domain portion of the uri + */ + inline const Aws::String& GetAuthority() const { return m_authority; } + + /** + * Sets the domain portion of the uri + */ + inline void SetAuthority(const Aws::String& value) { m_authority = value; } + + /** + * Gets the port portion of the uri, defaults to 22 for ftp, 80 for http and 443 for https + */ + inline uint16_t GetPort() const { return m_port; } + + /** + * Sets the port portion of the uri, normally you will not have to do this. If the scheme is set to ftp, http + * or https then the default ports will be set. + */ + inline void SetPort(uint16_t value) { m_port = value; } + + /** + * Gets the path portion of the uri e.g. the portion after the first slash after the authority and prior to the + * query string. This is not url encoded. + */ + inline const Aws::String& GetPath() const { return m_path; } + + /** + * Gets the path portion of the uri, url encodes it and returns it + */ + inline Aws::String GetURLEncodedPath() const { return URLEncodePath(m_path); } + + /** + * Sets the path portion of the uri. URL encodes it if needed + */ + void SetPath(const Aws::String& value); + + /** + * Gets the raw query string including the ? + */ + inline const Aws::String& GetQueryString() const { return m_queryString; } + + /** + * Resets the query string to the raw string. all query string manipulations made before this call will be lost + */ + void SetQueryString(const Aws::String& str); + + Aws::String GetFormParameters() const; + + /** + * Canonicalizes the query string. + */ + void CanonicalizeQueryString(); + + /** + * parses query string and returns url decoded key/value mappings from it. Spaces and all url encoded + * values will not be encoded. + */ + QueryStringParameterCollection GetQueryStringParameters(bool decode = true) const; + + /** + * Adds query string parameter to underlying query string. + */ + void AddQueryStringParameter(const char* key, const Aws::String& value); + + /** + * Adds multiple query string parameters to underlying query string. + */ + void AddQueryStringParameter(const Aws::Map<Aws::String, Aws::String>& queryStringPairs); + + /** + * Converts the URI to a String usable for its context. e.g. an http request. + */ + Aws::String GetURIString(bool includeQueryString = true) const; + + /** + * URLEncodes the path portions of path (doesn't encode the "/" portion) + * Keeps the first and the last "/". + */ + static Aws::String URLEncodePath(const Aws::String& path); + + /** + * URLEncodes the path portion of the URI according to RFC3986 + */ + static Aws::String URLEncodePathRFC3986(const Aws::String& path); + + private: + void ParseURIParts(const Aws::String& uri); + void ExtractAndSetScheme(const Aws::String& uri); + void ExtractAndSetAuthority(const Aws::String& uri); + void ExtractAndSetPort(const Aws::String& uri); + void ExtractAndSetPath(const Aws::String& uri); + void ExtractAndSetQueryString(const Aws::String& uri); + bool CompareURIParts(const URI& other) const; + + Scheme m_scheme; + Aws::String m_authority; + uint16_t m_port; + Aws::String m_path; + Aws::String m_queryString; + }; + + } // namespace Http +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/curl/CurlHandleContainer.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/curl/CurlHandleContainer.h new file mode 100644 index 0000000000..c2745753eb --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/curl/CurlHandleContainer.h @@ -0,0 +1,74 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/utils/ResourceManager.h> + +#include <utility> +#include <curl/curl.h> + +namespace Aws +{ +namespace Http +{ + +/** + * Simple Connection pool manager for Curl. It maintains connections in a thread safe manner. You + * can call into acquire a handle, then put it back when finished. It is assumed that reusing an already + * initialized handle is preferable (especially for synchronous clients). The pool doubles in capacity as + * needed up to the maximum amount of connections. + */ +class CurlHandleContainer +{ +public: + /** + * Initializes an empty stack of CURL handles. If you are only making synchronous calls via your http client + * then a small size is best. For async support, a good value would be 6 * number of Processors. * + */ + CurlHandleContainer(unsigned maxSize = 50, long httpRequestTimeout = 0, long connectTimeout = 1000, bool tcpKeepAlive = true, + unsigned long tcpKeepAliveIntervalMs = 30000, long lowSpeedTime = 3000, unsigned long lowSpeedLimit = 1); + ~CurlHandleContainer(); + + /** + * Blocks until a curl handle from the pool is available for use. + */ + CURL* AcquireCurlHandle(); + /** + * Returns a handle to the pool for reuse. It is imperative that this is called + * after you are finished with the handle. + */ + void ReleaseCurlHandle(CURL* handle); + + /** + * When the handle has bad DNS entries, problematic live connections, we need to destory the handle from pool. + */ + void DestroyCurlHandle(CURL* handle); + +private: + CurlHandleContainer(const CurlHandleContainer&) = delete; + const CurlHandleContainer& operator = (const CurlHandleContainer&) = delete; + CurlHandleContainer(const CurlHandleContainer&&) = delete; + const CurlHandleContainer& operator = (const CurlHandleContainer&&) = delete; + + CURL* CreateCurlHandleInPool(); + bool CheckAndGrowPool(); + void SetDefaultOptionsOnHandle(CURL* handle); + + Aws::Utils::ExclusiveOwnershipResourceManager<CURL*> m_handleContainer; + unsigned m_maxPoolSize; + unsigned long m_httpRequestTimeout; + unsigned long m_connectTimeout; + bool m_enableTcpKeepAlive; + unsigned long m_tcpKeepAliveIntervalMs; + unsigned long m_lowSpeedTime; + unsigned long m_lowSpeedLimit; + unsigned m_poolSize; + std::mutex m_containerLock; +}; + +} // namespace Http +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/curl/CurlHttpClient.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/curl/CurlHttpClient.h new file mode 100644 index 0000000000..31f96befd5 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/curl/CurlHttpClient.h @@ -0,0 +1,77 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/http/HttpClient.h> +#include <aws/core/http/curl/CurlHandleContainer.h> +#include <aws/core/client/ClientConfiguration.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <atomic> + +namespace Aws +{ +namespace Http +{ +namespace Standard +{ + class StandardHttpResponse; +} + +//Curl implementation of an http client. Right now it is only synchronous. +class AWS_CORE_API CurlHttpClient: public HttpClient +{ +public: + + using Base = HttpClient; + + //Creates client, initializes curl handle if it hasn't been created already. + CurlHttpClient(const Aws::Client::ClientConfiguration& clientConfig); + + //Makes request and receives response synchronously + std::shared_ptr<HttpResponse> MakeRequest(const std::shared_ptr<HttpRequest>& request, + Aws::Utils::RateLimits::RateLimiterInterface* readLimiter = nullptr, + Aws::Utils::RateLimits::RateLimiterInterface* writeLimiter = nullptr) const override; + + static void InitGlobalState(); + static void CleanupGlobalState(); + +protected: + /** + * Override any configuration on CURL handle for each request before sending. + * The usage is to have a subclass of CurlHttpClient and have your own implementation of this function to configure whatever you want on CURL handle. + */ + virtual void OverrideOptionsOnConnectionHandle(CURL*) const {} + +private: + mutable CurlHandleContainer m_curlHandleContainer; + bool m_isUsingProxy; + Aws::String m_proxyUserName; + Aws::String m_proxyPassword; + Aws::String m_proxyScheme; + Aws::String m_proxyHost; + Aws::String m_proxySSLCertPath; + Aws::String m_proxySSLCertType; + Aws::String m_proxySSLKeyPath; + Aws::String m_proxySSLKeyType; + Aws::String m_proxyKeyPasswd; + unsigned m_proxyPort; + bool m_verifySSL; + Aws::String m_caPath; + Aws::String m_caFile; + Aws::String m_proxyCaPath; + Aws::String m_proxyCaFile; + bool m_disableExpectHeader; + bool m_allowRedirects; + static std::atomic<bool> isInit; +}; + +using PlatformHttpClient = CurlHttpClient; + +} // namespace Http +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/standard/StandardHttpRequest.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/standard/StandardHttpRequest.h new file mode 100644 index 0000000000..c9c0016ef5 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/standard/StandardHttpRequest.h @@ -0,0 +1,89 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/http/HttpRequest.h> +#include <aws/core/utils/memory/stl/AWSMap.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ + namespace Http + { + namespace Standard + { + /** + * Simple STL container modeling of HttpRequest. Implementation of the HttpRequest interface. + */ + class AWS_CORE_API StandardHttpRequest : public HttpRequest + { + public: + /** + * Initializes an HttpRequest object with uri and http method. + */ + StandardHttpRequest(const URI& uri, HttpMethod method); + + /** + * Get All headers for this request. + */ + virtual HeaderValueCollection GetHeaders() const override; + /** + * Get the value for a Header based on its name. + * This function doesn't check the existence of headerName. + * So make sure you call HasHeader() first before calling this function, otherwise the behavior is undefined. + */ + virtual const Aws::String& GetHeaderValue(const char* headerName) const override; + /** + * Add a header pair + */ + virtual void SetHeaderValue(const char* headerName, const Aws::String& headerValue) override; + /** + * Add a header pair + */ + virtual void SetHeaderValue(const Aws::String& headerName, const Aws::String& headerValue) override; + /** + * delete pair by headerName + */ + virtual void DeleteHeader(const char* headerName) override; + /** + * Adds a content body stream to the request. This stream will be used to send the body to the endpoint. + */ + virtual inline void AddContentBody(const std::shared_ptr<Aws::IOStream>& strContent) override { bodyStream = strContent; } + /** + * Gets the content body stream that will be used for this request. + */ + virtual inline const std::shared_ptr<Aws::IOStream>& GetContentBody() const override { return bodyStream; } + /** + * Returns true if a header exists in the request with name + */ + virtual bool HasHeader(const char*) const override; + /** + * Get size in bytes of the request when as it will be going accross the wire. + */ + virtual int64_t GetSize() const override; + /** + * Gets the factory for creating the stream that will be used in the http response. + */ + virtual const Aws::IOStreamFactory& GetResponseStreamFactory() const override; + /** + * Sets the factory for creating the stream that will be used in the http response. + */ + virtual void SetResponseStreamFactory(const Aws::IOStreamFactory& factory) override; + + private: + HeaderValueCollection headerMap; + std::shared_ptr<Aws::IOStream> bodyStream; + Aws::IOStreamFactory m_responseStreamFactory; + Aws::String m_emptyHeader; + }; + + } // namespace Standard + } // namespace Http +} // namespace Aws + + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/standard/StandardHttpResponse.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/standard/StandardHttpResponse.h new file mode 100644 index 0000000000..309206f1f3 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/http/standard/StandardHttpResponse.h @@ -0,0 +1,74 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/http/HttpResponse.h> +#include <aws/core/utils/memory/stl/AWSMap.h> +#include <aws/core/utils/stream/ResponseStream.h> +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ + namespace Http + { + namespace Standard + { + /** + * Simple STL representation an Http Response, implements HttpResponse. + */ + class AWS_CORE_API StandardHttpResponse : public HttpResponse + { + public: + /** + * Initializes an http response with the originalRequest and the response code. + */ + StandardHttpResponse(const std::shared_ptr<const HttpRequest>& originatingRequest) : + HttpResponse(originatingRequest), + bodyStream(originatingRequest->GetResponseStreamFactory()) + {} + + ~StandardHttpResponse() = default; + + /** + * Get the headers from this response + */ + HeaderValueCollection GetHeaders() const; + /** + * Returns true if the response contains a header by headerName + */ + bool HasHeader(const char* headerName) const; + /** + * Returns the value for a header at headerName if it exists. + */ + const Aws::String& GetHeader(const Aws::String&) const; + /** + * Gets the response body of the response. + */ + inline Aws::IOStream& GetResponseBody() const { return bodyStream.GetUnderlyingStream(); } + /** + * Gives full control of the memory of the ResponseBody over to the caller. At this point, it is the caller's + * responsibility to clean up this object. + */ + inline Utils::Stream::ResponseStream&& SwapResponseStreamOwnership() { return std::move(bodyStream); } + /** + * Adds a header to the http response object. + */ + void AddHeader(const Aws::String&, const Aws::String&); + + private: + StandardHttpResponse(const StandardHttpResponse&); + + Aws::Map<Aws::String, Aws::String> headerMap; + Utils::Stream::ResponseStream bodyStream; + }; + + } // namespace Standard + } // namespace Http +} // namespace Aws + + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/internal/AWSHttpResourceClient.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/internal/AWSHttpResourceClient.h new file mode 100644 index 0000000000..c58a1b70bf --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/internal/AWSHttpResourceClient.h @@ -0,0 +1,225 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/AWSMemory.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/client/ClientConfiguration.h> +#include <aws/core/client/AWSErrorMarshaller.h> +#include <aws/core/auth/AWSCredentials.h> +#include <aws/core/AmazonWebServiceResult.h> +#include <aws/core/utils/DateTime.h> +#include <memory> +#include <mutex> +namespace Aws +{ + namespace Http + { + class HttpClient; + class HttpRequest; + enum class HttpResponseCode; + } // namespace Http + + namespace Internal + { + /** + * Simple client for accessing the AWS remote data by Http. + * Currently we use it to access EC2 Metadata and ECS Credential. + */ + class AWS_CORE_API AWSHttpResourceClient + { + public: + /** + * Builds an AWSHttpResourceClient instance by using default http stack. + */ + AWSHttpResourceClient(const char* logtag = "AWSHttpResourceClient"); + AWSHttpResourceClient(const Client::ClientConfiguration& clientConfiguration, const char* logtag = "AWSHttpResourceClient"); + + AWSHttpResourceClient& operator =(const AWSHttpResourceClient& rhs) = delete; + AWSHttpResourceClient(const AWSHttpResourceClient& rhs) = delete; + AWSHttpResourceClient& operator =(const AWSHttpResourceClient&& rhs) = delete; + AWSHttpResourceClient(const AWSHttpResourceClient&& rhs) = delete; + + virtual ~AWSHttpResourceClient(); + + /** + * Connects to an HTTP endpoint to read the specified resource and returns the text contents. + * The resource URI = endpoint + resourcePath (e.g:http://domain/path/to/res) + * @param endpoint The HTTP resource to connect to. + * @param resourcePath A path appended to the endpoint to form the final URI. + * @param authToken An optional authorization token that will be passed as the value of the HTTP + * header 'Authorization'. + * @return The response from the HTTP endpoint as a string. + */ + virtual Aws::String GetResource(const char* endpoint, const char* resourcePath, const char* authToken) const; + + /** + * Connects to an HTTP endpoint to read the specified resource and returns the text contents. + * The resource URI = endpoint + resourcePath (e.g:http://domain/path/to/res) + * @param endpoint The HTTP resource to connect to. + * @param resourcePath A path appended to the endpoint to form the final URI. + * @param authToken An optional authorization token that will be passed as the value of the HTTP + * header 'Authorization'. + * @return The response from the HTTP endpoint as a string, together with the http response code. + */ + virtual AmazonWebServiceResult<Aws::String> GetResourceWithAWSWebServiceResult(const char *endpoint, const char *resourcePath, const char *authToken) const; + + /** + * Above Function: Aws::String GetResource(const char* endpoint, const char* resourcePath, const char* authToken) const; + * is limited to HTTP GET method and caller can't add wanted HTTP headers as well. + * This overload gives caller the flexibility to manipulate the request, as well returns the HttpResponseCode of the last attempt. + */ + virtual AmazonWebServiceResult<Aws::String> GetResourceWithAWSWebServiceResult(const std::shared_ptr<Http::HttpRequest> &httpRequest) const; + + /** + * Set an error marshaller so as to marshall error type from http response body if any. + * So that it can work with retry strategy to decide if a request should retry or not. + */ + void SetErrorMarshaller(Aws::UniquePtr<Client::AWSErrorMarshaller> errorMarshaller) { m_errorMarshaller = std::move(errorMarshaller); } + const Client::AWSErrorMarshaller* GetErrorMarshaller() const { return m_errorMarshaller.get(); } + + protected: + Aws::String m_logtag; + + private: + std::shared_ptr<Client::RetryStrategy> m_retryStrategy; + std::shared_ptr<Http::HttpClient> m_httpClient; + Aws::UniquePtr<Client::AWSErrorMarshaller> m_errorMarshaller; + }; + + /** + * Derived class to support retrieving of EC2 Metadata + */ + class AWS_CORE_API EC2MetadataClient : public AWSHttpResourceClient + { + public: + /** + * Build an instance with default EC2 Metadata service endpoint + */ + EC2MetadataClient(const char* endpoint = "http://169.254.169.254"); + EC2MetadataClient(const Client::ClientConfiguration& clientConfiguration, const char* endpoint = "http://169.254.169.254"); + + EC2MetadataClient& operator =(const EC2MetadataClient& rhs) = delete; + EC2MetadataClient(const EC2MetadataClient& rhs) = delete; + EC2MetadataClient& operator =(const EC2MetadataClient&& rhs) = delete; + EC2MetadataClient(const EC2MetadataClient&& rhs) = delete; + + virtual ~EC2MetadataClient(); + + using AWSHttpResourceClient::GetResource; + + /** + * Connects to the metadata service to read the specified resource and + * returns the text contents. The resource URI = m_endpoint + resourcePath. + */ + virtual Aws::String GetResource(const char* resourcePath) const; + + /** + * Connects to the Amazon EC2 Instance Metadata Service to retrieve the + * default credential information (if any). + */ + virtual Aws::String GetDefaultCredentials() const; + + /** + * Connects to the Amazon EC2 Instance Metadata Service to retrieve the + * credential information (if any) in a more secure way. + */ + virtual Aws::String GetDefaultCredentialsSecurely() const; + + /** + * connects to the Amazon EC2 Instance metadata Service to retrieve the region + * the current EC2 instance is running in. + */ + virtual Aws::String GetCurrentRegion() const; + + private: + Aws::String m_endpoint; + mutable std::recursive_mutex m_tokenMutex; + mutable Aws::String m_token; + mutable bool m_tokenRequired; + mutable Aws::String m_region; + }; + + void AWS_CORE_API InitEC2MetadataClient(); + void AWS_CORE_API CleanupEC2MetadataClient(); + std::shared_ptr<EC2MetadataClient> AWS_CORE_API GetEC2MetadataClient(); + + /** + * Derived class to support retrieving of ECS Credentials + */ + class AWS_CORE_API ECSCredentialsClient : public AWSHttpResourceClient + { + public: + /** + * Build an instance with default ECS service endpoint + * @param resourcePath The path part of the metadata URL + * @param endpoint The URL authority to hit. Default is the IP address of the Task metadata service endpoint. + */ + ECSCredentialsClient(const char* resourcePath, const char* endpoint = "http://169.254.170.2", + const char* authToken = ""); + ECSCredentialsClient(const Client::ClientConfiguration& clientConfiguration, + const char* resourcePath, const char* endpoint = "http://169.254.170.2", + const char* authToken = ""); + + ECSCredentialsClient& operator =(ECSCredentialsClient& rhs) = delete; + ECSCredentialsClient(const ECSCredentialsClient& rhs) = delete; + ECSCredentialsClient& operator =(ECSCredentialsClient&& rhs) = delete; + ECSCredentialsClient(const ECSCredentialsClient&& rhs) = delete; + + /** + * Connects to the Amazon ECS service to retrieve the credential + */ + virtual Aws::String GetECSCredentials() const + { + return GetResource(m_endpoint.c_str(), m_resourcePath.c_str(), m_token.c_str()); + } + + private: + Aws::String m_resourcePath; + Aws::String m_endpoint; + Aws::String m_token; + }; + + /** + * To support retrieving credentials from STS. + * Note that STS accepts request with protocol of queryxml. Calling GetResource() will trigger + * a query request using AWSHttpResourceClient under the hood. + */ + class AWS_CORE_API STSCredentialsClient : public AWSHttpResourceClient + { + public: + /** + * Initializes the provider to retrieve credentials from STS when it expires. + */ + STSCredentialsClient(const Client::ClientConfiguration& clientConfiguration); + + STSCredentialsClient& operator =(STSCredentialsClient& rhs) = delete; + STSCredentialsClient(const STSCredentialsClient& rhs) = delete; + STSCredentialsClient& operator =(STSCredentialsClient&& rhs) = delete; + STSCredentialsClient(const STSCredentialsClient&& rhs) = delete; + + // If you want to make an AssumeRoleWithWebIdentity call to sts. use these classes to pass data to and get info from STSCredentialsClient client. + // If you want to make an AssumeRole call to sts, define the request/result members class/struct like this. + struct STSAssumeRoleWithWebIdentityRequest + { + Aws::String roleSessionName; + Aws::String roleArn; + Aws::String webIdentityToken; + }; + + struct STSAssumeRoleWithWebIdentityResult + { + Aws::Auth::AWSCredentials creds; + }; + + STSAssumeRoleWithWebIdentityResult GetAssumeRoleWithWebIdentityCredentials(const STSAssumeRoleWithWebIdentityRequest& request); + + private: + Aws::String m_endpoint; + }; + } // namespace Internal +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/CoreMetrics.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/CoreMetrics.h new file mode 100644 index 0000000000..575a6003e2 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/CoreMetrics.h @@ -0,0 +1,27 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/monitoring/HttpClientMetrics.h> + +namespace Aws +{ + namespace Monitoring + { + /** + * Metrics collected from AWS SDK Core include Http Client Metrics and other types of metrics. + */ + struct AWS_CORE_API CoreMetricsCollection + { + /** + * Metrics collected from underlying http client during execution of a request + */ + HttpClientMetricsCollection httpClientMetrics; + + // Add Other types of metrics here. + }; + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/DefaultMonitoring.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/DefaultMonitoring.h new file mode 100644 index 0000000000..148a3a23c5 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/DefaultMonitoring.h @@ -0,0 +1,73 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/client/AWSClient.h> +#include <aws/core/monitoring/MonitoringInterface.h> +#include <aws/core/monitoring/MonitoringFactory.h> +#include <aws/core/net/SimpleUDP.h> +namespace Aws +{ + namespace Monitoring + { + /** + * Default monitoring implementation definition + */ + class AWS_CORE_API DefaultMonitoring: public MonitoringInterface + { + public: + const static int DEFAULT_MONITORING_VERSION; + const static char DEFAULT_CSM_CONFIG_ENABLED[]; + const static char DEFAULT_CSM_CONFIG_CLIENT_ID[]; + const static char DEFAULT_CSM_CONFIG_HOST[]; + const static char DEFAULT_CSM_CONFIG_PORT[]; + const static char DEFAULT_CSM_ENVIRONMENT_VAR_ENABLED[]; + const static char DEFAULT_CSM_ENVIRONMENT_VAR_CLIENT_ID[]; + const static char DEFAULT_CSM_ENVIRONMENT_VAR_HOST[]; + const static char DEFAULT_CSM_ENVIRONMENT_VAR_PORT[]; + + /** + * @brief Construct a default monitoring instance + * @param clientId, used to identify the application + * @param host, either the host name or the host ip address (could be ipv4 or ipv6). Note that "localhost" will be treated as host name and address look up will be performed. + * @param port, used to send collected metric to a local agent listen on this port. + */ + DefaultMonitoring(const Aws::String& clientId, const Aws::String& host, unsigned short port); + + void* OnRequestStarted(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request) const override; + + void OnRequestSucceeded(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request, + const Aws::Client::HttpResponseOutcome& outcome, const CoreMetricsCollection& metricsFromCore, void* context) const override; + + + void OnRequestFailed(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request, + const Aws::Client::HttpResponseOutcome& outcome, const CoreMetricsCollection& metricsFromCore, void* context) const override; + + + void OnRequestRetry(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr<const Aws::Http::HttpRequest>& request, void* context) const override; + + + void OnFinish(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr<const Aws::Http::HttpRequest>& request, void* context) const override; + + static inline int GetVersion() { return DEFAULT_MONITORING_VERSION; } + private: + void CollectAndSendAttemptData(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr<const Aws::Http::HttpRequest>& request, const Aws::Client::HttpResponseOutcome& outcome, + const CoreMetricsCollection& metricsFromCore, void* context) const; + + Aws::Net::SimpleUDP m_udp; + Aws::String m_clientId; + }; + + class AWS_CORE_API DefaultMonitoringFactory : public MonitoringFactory + { + public: + Aws::UniquePtr<MonitoringInterface> CreateMonitoringInstance() const override; + }; + } // namespace Monitoring +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/HttpClientMetrics.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/HttpClientMetrics.h new file mode 100644 index 0000000000..2c2efa3ed5 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/HttpClientMetrics.h @@ -0,0 +1,84 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/memory/stl/AWSMap.h> + +namespace Aws +{ + namespace Monitoring + { + /** + * Metrics definitions optional from HttpClient module inside AWS Sdk core. + */ + enum class HttpClientMetricsType + { + /* + * Requires a successful DNS lookup, contains the (IPv4 or IPv6 as appropriate) numeric address of the connection endpoint to which the attempt was sent. + */ + DestinationIp = 0, + + /** + * Requires the SDK to recognize that an existing connection was reused to make the request, + * contains the time interval (in milliseconds) between the construction of the http request and when a connection was successfully acquired from the connection pool. + */ + AcquireConnectionLatency, + + /** + * Requires the SDK to recognize whether or not an existing connection was used to make the request, + * contains 1 if an existing connection was used to perform the http request; contains 0 if a new connection was opened to perform the http request. + */ + ConnectionReused, + + /** + * Requires the SDK to recognize that a new connection was established to make the request, + * contains the time interval (in milliseconds) between the construction of the http request and when a connection was fully established. + * If the SDK is able to estimate this time despite not having a perfectly accurate callback for the specific event, then it should. + * For example, if the http client includes user-level data write functions that are guaranteed to be called shortly after connection establishment, + * then the first call could be used as a reasonable time marker for ConnectLatency + */ + ConnectLatency, + + /** + * Requires the SDK to be able to mark the point in time where the request starts transmission, + * contains the time interval (in milliseconds) between when the request begins transmission to the service and when a terminal error has occurred or the response has been parsed, + * excluding streaming payloads. Like ConnectLatency, if the SDK has access to an event that is a "close enough" marker in time, it should include this entry. + * The request here is a http level request, not a service level API request. + */ + RequestLatency, + + /** + * Requires the SDK to have access to how long it took to perform DNS lookup, if it took place, + * contains the time (in milliseconds) it took to perform DNS lookup, during the Api Call attempt. + */ + DnsLatency, + + /** + * Requires the SDK to have access to how long it took to establish the underlying Tcp/Ip connection used for the request, + * contains the time (in milliseconds) it took to fully establish the TCP/IP connection used to make the request attempt. + */ + TcpLatency, + + /** + * Requires the SDK to have access to how long it took to perform the SSL handshake for a secure request, + * contains the time (in milliseconds) it took to perform a SSL handshake over the established TCP/IP connection. + */ + SslLatency, + + /** + * Unknow Metrics Type + */ + Unknown + }; + + typedef Aws::Map<Aws::String, int64_t> HttpClientMetricsCollection; + + AWS_CORE_API HttpClientMetricsType GetHttpClientMetricTypeByName(const Aws::String& name); + + AWS_CORE_API Aws::String GetHttpClientMetricNameByType(HttpClientMetricsType type); + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/MonitoringFactory.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/MonitoringFactory.h new file mode 100644 index 0000000000..2d03efa712 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/MonitoringFactory.h @@ -0,0 +1,26 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once +#include <aws/core/Core_EXPORTS.h> + +namespace Aws +{ + namespace Monitoring + { + class MonitoringInterface; + + /** + * Factory to create monitoring instance. + */ + class AWS_CORE_API MonitoringFactory + { + public: + virtual ~MonitoringFactory() = default; + virtual Aws::UniquePtr<MonitoringInterface> CreateMonitoringInstance() const = 0; + }; + + } // namespace Monitoring +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/MonitoringInterface.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/MonitoringInterface.h new file mode 100644 index 0000000000..ebe50722c7 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/MonitoringInterface.h @@ -0,0 +1,89 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/http/HttpResponse.h> +#include <aws/core/client/AWSError.h> +#include <aws/core/client/AWSClient.h> +#include <aws/core/monitoring/CoreMetrics.h> + +namespace Aws +{ + namespace Monitoring + { + /** + * Monitoring interface definition for SDK metrics collection. + */ + class AWS_CORE_API MonitoringInterface + { + public: + virtual ~MonitoringInterface() = default; + + /** + * @brief This function lets you do preparation work when a http attempt(request) starts. It returns a pointer to an implementation defined context which will be + * passed down with the other facilities that completes the request's lifetime. This context can be used to track the lifetime of the request and record metrics + * specific to this particular request. You are responsible for deleteing the context during your OnFinish call. + * @param serviceName, the service client who initiates this http attempt. like "s3", "ec2", etc. + * @param requestName, the operation or API name of this http attempt, like "GetObject" in s3. + * @param request, the actual Http Request. + * @return implementation depends memory address of context. + */ + virtual void* OnRequestStarted(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr<const Aws::Http::HttpRequest>& request) const = 0; + + /** + * @brief Once a Http attempt finished and received "Succeeded" response, this function will be called. + * @param serviceName, the service client who initiate this http attempt. like "s3", "ec2", etc. + * @param requestName, the operation or API name of this http attempt, like "GetObject" in s3. + * @param request, the actual Http Request. + * @param outcome, the outcome of the http attempt, you can access httpResponse and original httpRequest from it. + * @param metricsFromCore, metrics collected from core, such as detailed latencies during http connection. + * @param context parameter pointed to the same place returned by OnRequestStarted() function. + * @return void. + */ + virtual void OnRequestSucceeded(const Aws::String& serviceName, + const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request, + const Aws::Client::HttpResponseOutcome& outcome, const CoreMetricsCollection& metricsFromCore, void* context) const = 0; + + /** + * @brief Once a Http request finished and received "Failed" response, this function will be called. + * @param serviceName, the service client who initiate this http attempt. like "s3", "ec2", etc. + * @param requestName, the operation or API name of this http attempt, like "GetObject" in s3. + * @param request, the actual Http Request. + * @param outcome, the outcome of the http attempt, you can access httpResponse and original httpRequest from it. + * @param metricsFromCore, metrics collected from core, such as detailed latencies during http connection. + * @param context parameter pointed to the same place returned by OnRequestStarted() function. + * @return void. + */ + virtual void OnRequestFailed(const Aws::String& serviceName, + const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request, + const Aws::Client::HttpResponseOutcome& outcome, const CoreMetricsCollection& metricsFromCore, void* context) const = 0; + + /** + * @brief Once an API call retried the attempt and send the request again, this function will be called. + * @param serviceName, the service client who initiate this http attempt. like "s3", "ec2", etc. + * @param requestName, the operation or API name of this http attempt, like "GetObject" in s3. + * @param request, the actual Http Request. + * @param context parameter pointed to the same place returned by OnRequestStarted() function. + * @return void. + */ + virtual void OnRequestRetry(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr<const Aws::Http::HttpRequest>& request, void* context) const = 0; + + /** + * @brief This function will always be called by the SDK to signal the implementer that this request is done. The implementer can safely delete the context. + * @param serviceName, the service client who initiate this http attempt. like "s3", "ec2", etc. + * @param requestName, the operation or API name of this http attempt, like "GetObject" in s3. + * @param request, the actual Http Request. + * @param context parameter pointed to the same place returned by OnRequestStarted() function. + * @return void. + */ + virtual void OnFinish(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr<const Aws::Http::HttpRequest>& request, void* context) const = 0; + }; + } // namespace Monitoring +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/MonitoringManager.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/MonitoringManager.h new file mode 100644 index 0000000000..aaa5bca5d1 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/monitoring/MonitoringManager.h @@ -0,0 +1,64 @@ + +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/memory/stl/AWSVector.h> +#include <aws/core/client/AWSClient.h> +#include <aws/core/monitoring/CoreMetrics.h> + +namespace Aws +{ + namespace Monitoring + { + class MonitoringFactory; + /** + * Wrapper function of OnRequestStarted defined by all monitoring instances + */ + Aws::Vector<void*> OnRequestStarted(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr<const Aws::Http::HttpRequest>& request); + + /** + * Wrapper function of OnRequestSucceeded defined by all monitoring instances + */ + void OnRequestSucceeded(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request, + const Aws::Client::HttpResponseOutcome& outcome, const CoreMetricsCollection& metricsFromCore, const Aws::Vector<void*>& contexts); + + /** + * Wrapper function of OnRequestFailed defined by all monitoring instances + */ + void OnRequestFailed(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request, + const Aws::Client::HttpResponseOutcome& outcome, const CoreMetricsCollection& metricsFromCore, const Aws::Vector<void*>& contexts); + + /** + * Wrapper function of OnRequestRetry defined by all monitoring instances + */ + void OnRequestRetry(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr<const Aws::Http::HttpRequest>& request, const Aws::Vector<void*>& contexts); + + /** + * Wrapper function of OnFinish defined by all monitoring instances + */ + void OnFinish(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr<const Aws::Http::HttpRequest>& request, const Aws::Vector<void*>& contexts); + + typedef std::function<Aws::UniquePtr<MonitoringFactory>()> MonitoringFactoryCreateFunction; + + /** + * Init monitoring using supplied factories, monitoring can support multiple instances. + * We will try to (based on config resolution result) create a default client side monitoring listener instance defined in AWS SDK Core module. + * and create other instances from these factories. + * This function will be called during Aws::InitAPI call, argument is acquired from Aws::SDKOptions->MonitoringOptions + */ + AWS_CORE_API void InitMonitoring(const std::vector<MonitoringFactoryCreateFunction>& monitoringFactoryCreateFunctions); + + /** + * Clean up monitoring related global variables + */ + AWS_CORE_API void CleanupMonitoring(); + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/net/Net.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/net/Net.h new file mode 100644 index 0000000000..00aca57e0a --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/net/Net.h @@ -0,0 +1,23 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +namespace Aws +{ + namespace Net + { + // Has network stack been initiated. + bool IsNetworkInitiated(); + + // Initiate network stack. + void InitNetwork(); + + // Cleanup network stack. + void CleanupNetwork(); + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/net/SimpleUDP.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/net/SimpleUDP.h new file mode 100644 index 0000000000..2e96b509fb --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/net/SimpleUDP.h @@ -0,0 +1,163 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <cstdint> +struct sockaddr; + +namespace Aws +{ + namespace Net + { + // 8K is aligned with default monitoring packet size. + const static size_t UDP_BUFFER_SIZE = 8192; + /** + * SimpleUDP definition. + */ + class AWS_CORE_API SimpleUDP + { + public: + /** + * @brief Constructor of SimpleUDP + * @param addressFamily, AF_INET for IPV4 or AF_INET6 for IPV6 + * @param sendBufSize, if nonzero, try set socket's send buffer size to this value. + * @param receieveBufSize, if nonzero, try set socket's receive buffer size to this value. + * @param nonBlocking, if it is true, implementation will try to create a non-blocking underlying UDP socket. + * Implementation should create and set the underlying udp socket. + */ + SimpleUDP(int addressFamily, size_t sendBufSize = UDP_BUFFER_SIZE, size_t receiveBufSize = UDP_BUFFER_SIZE, bool nonBlocking = true); + + /** + * @brief An easy constructor of an IPV4 or IPV6 SimpleUDP + * @param addressFamily, either AF_INET for IPV4 or AF_INET6 for IPV6 + * @param sendBufSize, if nonzero, try set socket's send buffer size to this value. + * @param receieveBufSize, if nonzero, try set socket's receive buffer size to this value. + * @param nonBlocking, if it is true, implementation will try to create a non-blocking underlying UDP socket. + * Implementation should create and set the underlying udp socket. + */ + SimpleUDP(bool IPV4 = true, size_t sendBufSize = UDP_BUFFER_SIZE, size_t receiveBufSize = UDP_BUFFER_SIZE, bool nonBlocking = true); + + /** + * @brief An easy constructor of SimpleUDP based on host and port + * @param host, the host that packets will be sent to, could be ipv4 or ipv6 address, or a hostname + * Note that "localhost" is not necessarily bind to 127.0.0.1, it could bind to ipv6 address ::1, or other type of ip addresses. If you pass localhost here, we will go through getaddrinfo procedure on Linux and Windows. + * @param port, the port number that the host listens on. + * @param sendBufSize, if nonzero, try set socket's send buffer size to this value. + * @param receieveBufSize, if nonzero, try set socket's receive buffer size to this value. + * @param nonBlocking, if it is true, implementation will try to create a non-blocking underlying UDP socket. + * Implementation should create and set the underlying udp socket. + */ + SimpleUDP(const char* host, unsigned short port, size_t sendBufSize = UDP_BUFFER_SIZE, size_t receiveBufSize = UDP_BUFFER_SIZE, bool nonBlocking = true); + + ~SimpleUDP(); + + /** + * @brief Connect underlying udp socket to server specified in address. + * @param address, the server's address info. + * @param addressLength, length of address, structure of address can vary. + * @return 0 on success, -1 on error, check errno for detailed error information. + */ + int Connect(const sockaddr* address, size_t addressLength); + + /** + * @brief An easy way to connect to host + * @param hostIP, a valid ipv4 or ipv6 address. The address type should match the m_addressFamily type settled during construction. + * Otherwise the connection will fail. + * @param port, the port that host listens on. + */ + int ConnectToHost(const char* hostIP, unsigned short port) const; + + /** + * @brief An easy way to connect to 127.0.0.1 or ::1 based on m_addressFamily + */ + int ConnectToLocalHost(unsigned short port) const; + + /** + * @brief Bind underlying udp socket to an address. + * @param address, the server's address info. + * @param addressLength, length of address, structure of address can vary. + * @return 0 on success, -1 on error, check errno for detailed error information. + */ + int Bind(const sockaddr* address, size_t addressLength) const; + + /** + * @brief An easy way to bind to localhost + */ + int BindToLocalHost(unsigned short port) const; + + /** + * @brief Send data to server without specifying address, only usable if hostIP and port are available. + * @param data, the data you want to send. + * @param dataLen, the length of data you want to send. On Windows, dataLen larger than INT32_MAX will cause undefined behavior + * @return 0 on success, -1 on error, check errno for detailed error information. + */ + int SendData(const uint8_t* data, size_t dataLen) const; + + /** + * @brief Send data to server. + * @param address, the server's address info. + * @param addressLength, length of address, structure of address can vary. + * @param data, the memory address of the data you want to send. + * @param dataLen, the length of data you want to send. On Windows, dataLen larger than INT32_MAX will cause undefined behavior + * @return 0 on success, -1 on error check errno for detailed error information. + */ + int SendDataTo(const sockaddr* address, size_t addressLength, const uint8_t* data, size_t dataLen) const; + + /** + * @brief An easy way to send data to localhost, when the underlying udp is connected, call this function will + * send the data to where it connects to, not essentially to localhost. when it's not connected, it will send data + * to localhost, but this call will not connect underlying socket to localhost for you. + * @param data, the memory address of the data you want to send. + * @param dataLen, the length of data you want to send. On Windows, dataLen larger than INT32_MAX will cause undefined behavior + * @param port, port of localhost. + * @return 0 on success, -1 on error, check errno for detailed error information. + */ + int SendDataToLocalHost(const uint8_t* data, size_t dataLen, unsigned short port) const; + + /** + * @brief Receive data from unique address specified in ConnectWithServer call. + * this function is equivalent to call ReceiveDataFrom(nullptr, 0, data, dataLen, flags). + * @param buffer, the memory address where you want to store received data. + * @param bufferLen, the size of data buffer. + * @return -1 on failure, check errno for detailed error information, on success, returns the actual bytes of data received + */ + int ReceiveData(uint8_t* buffer, size_t bufferLen) const; + + /** + * @brief Receive data from network. + * @param address, if not null and underlying implementation supply the incoming data's source address, this will be filled with source address info. + * @param addressLength, the size of source adddress, should not be null. + * @param buffer, the memory address where you want to store received data. + * @param bufferLen, the size of data buffer. + * @return -1 on failure, check errno for detailed error information, on success, returns the actual bytes of data received. + */ + int ReceiveDataFrom(sockaddr* address, size_t* addressLength, uint8_t* buffer, size_t bufferLen) const; + + /** + * Gets the AddressFamily used for the underlying socket. E.g. AF_INET, AF_INET6 etc. + */ + inline int GetAddressFamily() const { return m_addressFamily; } + + /** + * Is the underlying socket connected with a remote address + */ + inline bool IsConnected() const { return m_connected; } + + private: + void CreateSocket(int addressFamily, size_t sendBufSize, size_t receiveBufSize, bool nonBlocking); + int GetUnderlyingSocket() const { return m_socket; } + void SetUnderlyingSocket(int socket) { m_socket = socket; } + int m_addressFamily; + // if not connected, you can't perform SendData, if connected, SendDataTo will call SendData + mutable bool m_connected; + int m_socket; + unsigned short m_port; + Aws::String m_hostIP; + }; + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/Android.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/Android.h new file mode 100644 index 0000000000..b012a49d50 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/Android.h @@ -0,0 +1,29 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#ifdef __ANDROID__ + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSString.h> + +#include <jni.h> + +namespace Aws +{ +namespace Platform +{ + +// must be called before any other native SDK functions when running on Android +AWS_CORE_API void InitAndroid(JNIEnv* env, jobject context); + +// helper functions for functionality requiring JNI calls; not valid until InitAndroid has been called +AWS_CORE_API JavaVM* GetJavaVM(); +AWS_CORE_API const char* GetCacheDirectory(); + +} //namespace Platform +} //namespace Aws + +#endif // __ANDROID__ diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/Environment.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/Environment.h new file mode 100644 index 0000000000..f522bf3a22 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/Environment.h @@ -0,0 +1,22 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ +namespace Environment +{ + /** + * shim for getenv + */ + AWS_CORE_API Aws::String GetEnv(const char* name); + +} // namespace Environment +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/FileSystem.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/FileSystem.h new file mode 100644 index 0000000000..5eeacd2fbd --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/FileSystem.h @@ -0,0 +1,226 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSVector.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/memory/stl/AWSMap.h> +#include <functional> + +namespace Aws +{ + +namespace FileSystem +{ + struct DirectoryEntry; + class Directory; + + #ifdef _WIN32 + static const char PATH_DELIM = '\\'; + #else + static const char PATH_DELIM = '/'; + #endif + + /** + * Returns the directory path for the home dir env variable + */ + AWS_CORE_API Aws::String GetHomeDirectory(); + + /** + * Returns the directory path for the directory containing the currently running executable + */ + AWS_CORE_API Aws::String GetExecutableDirectory(); + + /** + * @brief Creates directory if it doesn't exist. Returns true if the directory was created or already exists. False for failure. + * @param path, the absolute path of the directory. + * @param createParentDirs, if true, then this function will create missing directories on the path like linux command: mkdir -p + */ + AWS_CORE_API bool CreateDirectoryIfNotExists(const char* path, bool createParentDirs = false); + + /** + * Creates directory if it doesn't exist. Returns true if the directory was created + * or already exists. False for failure. + */ + AWS_CORE_API bool RemoveDirectoryIfExists(const char* path); + + /** + * Deletes file if it exists. Returns true if file doesn't exist or on success. + */ + AWS_CORE_API bool RemoveFileIfExists(const char* fileName); + + /** + * Moves the file. Returns true on success + */ + AWS_CORE_API bool RelocateFileOrDirectory(const char* from, const char* to); + + /** + * Copies a directory and all of its contents. + */ + AWS_CORE_API bool DeepCopyDirectory(const char* from, const char* to); + + /** + * Deletes a directory and all of its contents. + */ + AWS_CORE_API bool DeepDeleteDirectory(const char* toDelete); + + /** + * Computes a unique tmp file path + */ + AWS_CORE_API Aws::String CreateTempFilePath(); + + /** + * Opens a directory for traversal. + */ + AWS_CORE_API Aws::UniquePtr<Directory> OpenDirectory(const Aws::String& path, const Aws::String& relativePath = ""); + + /** + * Joins the leftSegment and rightSegment of a path together using platform specific delimiter. + * e.g. C:\users\name\ and .aws becomes C:\users\name\.aws + */ + AWS_CORE_API Aws::String Join(const Aws::String& leftSegment, const Aws::String& rightSegment); + + /** + * Joins the leftSegment and rightSegment of a path together using the specified delimiter. + * e.g. with delimiter & C:\users\name\ and .aws becomes C:\users\name&.aws + */ + AWS_CORE_API Aws::String Join(char delimiter, const Aws::String& leftSegment, const Aws::String& rightSegment); + + /** + * Type of directory entry encountered. + */ + enum class FileType + { + None, + File, + Symlink, + Directory + }; + + struct DirectoryEntry + { + DirectoryEntry() : fileType(FileType::None), fileSize(0) {} + + operator bool() const { return !path.empty() && fileType != FileType::None; } + + Aws::String path; + Aws::String relativePath; + FileType fileType; + int64_t fileSize; + }; + + /** + * Base level representation of a directory. Provides the ability to iterate all entries in a directory and to descend into directories. + * We don't recommend you use this class directly. Instead see DirectoryTree. + */ + class AWS_CORE_API Directory + { + public: + virtual ~Directory() = default; + + /** + * Initialize a directory with it's absolute path. If the path is invalid, the bool operator will return false. + */ + Directory(const Aws::String& path, const Aws::String& relativePath); + + /** + * If this directory is valid for use. + */ + virtual operator bool() const { return m_directoryEntry.operator bool(); } + + /** + * Get the entry representing this current directory object. + */ + const DirectoryEntry& GetDirectoryEntry() const { return m_directoryEntry; } + + /** + * Get the current path of this directory object. + */ + const Aws::String& GetPath() const { return m_directoryEntry.path; } + + /** + * Get the next entry inside this directory. + */ + virtual DirectoryEntry Next() = 0; + + /** + * Descend into a directory if it is a directory. Returns a shared pointer to a Directory object which you can then call Next() and Descend on. + * The original Directory object you use is responsible for the memory this method allocates, so do not attempt to delete the return value. + */ + Aws::UniquePtr<Directory> Descend(const DirectoryEntry& directoryEntry); + + /** + * Recursively search directories with path as root directory, return all normal(non directory and non symlink) files' paths. + */ + static Aws::Vector<Aws::String> GetAllFilePathsInDirectory(const Aws::String& path); + + protected: + DirectoryEntry m_directoryEntry; + }; + + class DirectoryTree; + + /** + * Visitor for a Directory Tree traversal. Return true to continue the traversal, false to exit the traversal immediately. + */ + typedef std::function<bool(const DirectoryTree*, const DirectoryEntry&)> DirectoryEntryVisitor; + + /** + * Wrapper around directory. Currently provides a Depth-first and Breadth-first traversal of the provided path. This is most likely the class you are + * looking for. + */ + class AWS_CORE_API DirectoryTree + { + public: + /** + * Create a directory object for use with traversal using the provided path. + */ + DirectoryTree(const Aws::String& path); + + /** + * Returns true if the Directory Tree structures match. Otherwise false. + */ + bool operator==(DirectoryTree& other); + + /** + * Returns true if the Directory tree structure at path matches. Otherwise false. + */ + bool operator==(const Aws::String& path); + + /** + * Computes the difference between two directory trees based on their relative paths. + * File contents are not taken into account, only the tree structure. + * + * Returns the diff between the two trees where the key is the relative path. The Directory entry will + * contain the absolute path and file size. + */ + Aws::Map<Aws::String, DirectoryEntry> Diff(DirectoryTree& other); + + /** + * If the object is valid for use: true. Otherwise: false. + */ + operator bool() const; + + /** + * Performs a depth-first traversal of the directory tree. Upon encountering an entry, visitor will be invoked. + * If postOrder is true, a pre-order traversal will be used. otherwise pre-order will be used. + */ + void TraverseDepthFirst(const DirectoryEntryVisitor& visitor, bool postOrderTraversal = false); + + /** + * Performs a breadth-first traversal of the directory tree. Upon encountering an entry, visitor will be invoked. + */ + void TraverseBreadthFirst(const DirectoryEntryVisitor& visitor); + + private: + bool TraverseDepthFirst(Directory& dir, const DirectoryEntryVisitor& visitor, bool postOrder = false); + void TraverseBreadthFirst(Directory& dir, const DirectoryEntryVisitor& visitor); + + Aws::UniquePtr<Directory> m_dir; + }; + +} // namespace FileSystem +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/OSVersionInfo.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/OSVersionInfo.h new file mode 100644 index 0000000000..e9aa3ea1f0 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/OSVersionInfo.h @@ -0,0 +1,27 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ +namespace OSVersionInfo +{ + /** + * computing the version string for the current running operating system. + */ + AWS_CORE_API Aws::String ComputeOSVersionString(); + + /** + * runs a (shell) command string and returns the output; not needed on windows currently + */ + AWS_CORE_API Aws::String GetSysCommandOutput(const char* command); + +} // namespace OSVersionInfo +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/Platform.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/Platform.h new file mode 100644 index 0000000000..e1cae5262e --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/Platform.h @@ -0,0 +1,9 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/platform/Android.h> + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/Security.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/Security.h new file mode 100644 index 0000000000..d1533dd19f --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/Security.h @@ -0,0 +1,24 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <stddef.h> + +namespace Aws +{ +namespace Security +{ + + /* + * Securely clears a block of memory + */ + AWS_CORE_API void SecureMemClear(unsigned char *data, size_t length); + +} // namespace Security +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/Time.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/Time.h new file mode 100644 index 0000000000..ecf802db66 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/platform/Time.h @@ -0,0 +1,32 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <ctime> + +namespace Aws +{ +namespace Time +{ + + /* + * A platform-agnostic implementation of the timegm function from gnu extensions + */ + AWS_CORE_API time_t TimeGM(tm* const t); + + /* + * Converts from a time value of std::time_t type to a C tm structure for easier date analysis + */ + AWS_CORE_API void LocalTime(tm* t, std::time_t time); + + /* + * Converts from a time value of std::time_t type to a C tm structure for easier date analysis + */ + AWS_CORE_API void GMTime(tm* t, std::time_t time); + +} // namespace Time +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/ARN.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/ARN.h new file mode 100644 index 0000000000..7df956022d --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/ARN.h @@ -0,0 +1,58 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + #pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ + namespace Utils + { + /** + * ARN (Amazon Resource Name) is used to identify an unique resource on AWS. + * A full qualified ARN has two forms: + * 1. arn:partition:service:region:account-id:resource-type:resource-id:qualifier + * 2. arn:partition:service:region:account-id:resource-type/resource-id/qualifier + * Different services have different resource definition, here we treat anything + * after "[account-id]:" as resource. Service should have their own resource parser. + */ + class AWS_CORE_API ARN + { + public: + ARN(const Aws::String& arnString); + /** + * return if the ARN is valid after construction. + */ + explicit operator bool() const { return m_valid; } + + /** + * Get the originating arn string. + */ + const Aws::String& GetARNString() const { return m_arnString; } + + const Aws::String& GetPartition() const { return m_partition; } + + const Aws::String& GetService() const { return m_service; } + + const Aws::String& GetRegion() const { return m_region; } + + const Aws::String& GetAccountId() const { return m_accountId; } + + const Aws::String& GetResource() const { return m_resource; } + + private: + Aws::String m_arnString; + Aws::String m_partition; + Aws::String m_service; + Aws::String m_region; + Aws::String m_accountId; + Aws::String m_resource; + + bool m_valid; + }; + } +}
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/Array.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/Array.h new file mode 100644 index 0000000000..2b5bbc566d --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/Array.h @@ -0,0 +1,250 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/AWSMemory.h> +#include <aws/core/utils/memory/stl/AWSVector.h> +#include <memory> +#include <cassert> +#include <cstring> +#include <algorithm> + +#ifdef _WIN32 + +#include <iterator> + +#endif // _WIN32 + +namespace Aws +{ + namespace Utils + { + static const char* ARRAY_ALLOCATION_TAG = "Aws::Array"; + + /** + * Safe array class with move and copy semantics. + */ + template<typename T> + class Array + { + + public: + /** + * Create new empty array of size arraySize. Default argument is 0. If it is empty then no allocation happens. + */ + Array(size_t arraySize = 0) : + m_size(arraySize), + m_data(arraySize > 0 ? Aws::MakeUniqueArray<T>(arraySize, ARRAY_ALLOCATION_TAG) : nullptr) + { + } + + /** + * Create new array and initialize it to a raw array + */ + Array(const T* arrayToCopy, size_t arraySize) : + m_size(arraySize), + m_data(nullptr) + { + if (arrayToCopy != nullptr && m_size > 0) + { + m_data.reset(Aws::NewArray<T>(m_size, ARRAY_ALLOCATION_TAG)); + +#ifdef _WIN32 + std::copy(arrayToCopy, arrayToCopy + arraySize, stdext::checked_array_iterator< T * >(m_data.get(), m_size)); +#else + std::copy(arrayToCopy, arrayToCopy + arraySize, m_data.get()); +#endif // MSVC + } + } + + /** + * Merge multiple arrays into one + */ + Array(Aws::Vector<Array*>&& toMerge) + { + size_t totalSize = 0; + for(auto& array : toMerge) + { + totalSize += array->m_size; + } + + m_size = totalSize; + m_data.reset(Aws::NewArray<T>(m_size, ARRAY_ALLOCATION_TAG)); + + size_t location = 0; + for(auto& arr : toMerge) + { + if(arr->m_size > 0 && arr->m_data) + { + size_t arraySize = arr->m_size; +#ifdef _WIN32 + std::copy(arr->m_data.get(), arr->m_data.get() + arraySize, stdext::checked_array_iterator< T * >(m_data.get() + location, m_size)); +#else + std::copy(arr->m_data.get(), arr->m_data.get() + arraySize, m_data.get() + location); +#endif // MSVC + location += arraySize; + } + } + } + + Array(const Array& other) + { + m_size = other.m_size; + m_data = nullptr; + + if (m_size > 0) + { + m_data.reset(Aws::NewArray<T>(m_size, ARRAY_ALLOCATION_TAG)); + +#ifdef _WIN32 + std::copy(other.m_data.get(), other.m_data.get() + other.m_size, stdext::checked_array_iterator< T * >(m_data.get(), m_size)); +#else + std::copy(other.m_data.get(), other.m_data.get() + other.m_size, m_data.get()); +#endif // MSVC + } + } + + //move c_tor + Array(Array&& other) : + m_size(other.m_size), + m_data(std::move(other.m_data)) + { + other.m_size = 0; + other.m_data = nullptr; + } + + virtual ~Array() = default; + + Array& operator=(const Array& other) + { + if (this == &other) + { + return *this; + } + + m_size = other.m_size; + m_data = nullptr; + + if (m_size > 0) + { + m_data.reset(Aws::NewArray<T>(m_size, ARRAY_ALLOCATION_TAG)); + +#ifdef _WIN32 + std::copy(other.m_data.get(), other.m_data.get() + other.m_size, stdext::checked_array_iterator< T * >(m_data.get(), m_size)); +#else + std::copy(other.m_data.get(), other.m_data.get() + other.m_size, m_data.get()); +#endif // MSVC + } + + return *this; + } + + Array& operator=(Array&& other) + { + m_size = other.m_size; + m_data = std::move(other.m_data); + + return *this; + } + + bool operator==(const Array& other) const + { + if (this == &other) + return true; + + if (m_size == 0 && other.m_size == 0) + { + return true; + } + + if (m_size == other.m_size && m_data && other.m_data) + { + for (unsigned i = 0; i < m_size; ++i) + { + if (m_data.get()[i] != other.m_data.get()[i]) + return false; + } + + return true; + } + + return false; + } + + bool operator!=(const Array& other) const + { + return !(*this == other); + } + + T const& GetItem(size_t index) const + { + assert(index < m_size); + return m_data.get()[index]; + } + + T& GetItem(size_t index) + { + assert(index < m_size); + return m_data.get()[index]; + } + + T& operator[](size_t index) + { + return GetItem(index); + } + + T const& operator[](size_t index) const + { + return GetItem(index); + } + + inline size_t GetLength() const + { + return m_size; + } + + inline T* GetUnderlyingData() const + { + return m_data.get(); + } + + protected: + size_t m_size; + + Aws::UniqueArrayPtr<T> m_data; + }; + + typedef Array<unsigned char> ByteBuffer; + + /** + * Buffer for cryptographic operations. It zeroes itself back out upon deletion. Everything else is identical + * to byte buffer. + */ + class AWS_CORE_API CryptoBuffer : public ByteBuffer + { + public: + CryptoBuffer(size_t arraySize = 0) : ByteBuffer(arraySize) {} + CryptoBuffer(const unsigned char* arrayToCopy, size_t arraySize) : ByteBuffer(arrayToCopy, arraySize) {} + CryptoBuffer(Aws::Vector<ByteBuffer*>&& toMerge) : ByteBuffer(std::move(toMerge)) {} + CryptoBuffer(const ByteBuffer& other) : ByteBuffer(other) {} + CryptoBuffer(const CryptoBuffer& other) : ByteBuffer(other) {} + CryptoBuffer(CryptoBuffer&& other) : ByteBuffer(std::move(other)) {} + CryptoBuffer& operator=(const CryptoBuffer&) = default; + CryptoBuffer& operator=(CryptoBuffer&& other) { ByteBuffer::operator=(std::move(other)); return *this; } + bool operator==(const CryptoBuffer& other) const { return ByteBuffer::operator==(other); } + bool operator!=(const CryptoBuffer& other) const { return ByteBuffer::operator!=(other); } + + ~CryptoBuffer() { Zero(); } + + Array<CryptoBuffer> Slice(size_t sizeOfSlice) const; + CryptoBuffer& operator^(const CryptoBuffer& operand); + void Zero(); + }; + + } // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/DNS.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/DNS.h new file mode 100644 index 0000000000..7472a386c0 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/DNS.h @@ -0,0 +1,18 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ + namespace Utils + { + AWS_CORE_API bool IsValidDnsLabel(const Aws::String& label); + + AWS_CORE_API bool IsValidHost(const Aws::String& host); + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/DateTime.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/DateTime.h new file mode 100644 index 0000000000..a410279011 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/DateTime.h @@ -0,0 +1,250 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <chrono> + +namespace Aws +{ + namespace Utils + { + enum class DateFormat + { + RFC822, //for http headers + ISO_8601, //for query and xml payloads + ISO_8601_BASIC, // for retry headers and signers + AutoDetect + }; + + enum class Month + { + January = 0, + February, + March, + April, + May, + June, + July, + August, + September, + October, + November, + December + }; + + enum class DayOfWeek + { + Sunday = 0, + Monday, + Tuesday, + Wednesday, + Thursday, + Friday, + Saturday + }; + + /** + * Wrapper for all the weird crap we need to do with timestamps. + */ + class AWS_CORE_API DateTime + { + public: + /** + * Initializes time point to epoch + */ + DateTime(); + + /** + * Initializes time point to any other arbitrary timepoint + */ + DateTime(const std::chrono::system_clock::time_point& timepointToAssign); + + /** + * Initializes time point to millis Since epoch + */ + DateTime(int64_t millisSinceEpoch); + + /** + * Initializes time point to epoch time in seconds.millis + */ + DateTime(double epoch_millis); + + /** + * Initializes time point to value represented by timestamp and format. + */ + DateTime(const Aws::String& timestamp, DateFormat format); + + /** + * Initializes time point to value represented by timestamp and format. + */ + DateTime(const char* timestamp, DateFormat format); + + bool operator == (const DateTime& other) const; + bool operator < (const DateTime& other) const; + bool operator > (const DateTime& other) const; + bool operator != (const DateTime& other) const; + bool operator <= (const DateTime& other) const; + bool operator >= (const DateTime& other) const; + + DateTime operator+(const std::chrono::milliseconds& a) const; + DateTime operator-(const std::chrono::milliseconds& a) const; + + /** + * Assign from seconds.millis since epoch. + */ + DateTime& operator=(double secondsSinceEpoch); + + /** + * Assign from millis since epoch. + */ + DateTime& operator=(int64_t millisSinceEpoch); + + /** + * Assign from another time_point + */ + DateTime& operator=(const std::chrono::system_clock::time_point& timepointToAssign); + + /** + * Assign from an ISO8601 or RFC822 formatted string + */ + DateTime& operator=(const Aws::String& timestamp); + + /** + * Whether or not parsing the timestamp from string was successful. + */ + inline bool WasParseSuccessful() const { return m_valid; } + + /** + * Convert dateTime to local time string using predefined format. + */ + Aws::String ToLocalTimeString(DateFormat format) const; + + /** + * Convert dateTime to local time string using arbitrary format. + */ + Aws::String ToLocalTimeString(const char* formatStr) const; + + /** + * Convert dateTime to GMT time string using predefined format. + */ + Aws::String ToGmtString(DateFormat format) const; + + /** + * Convert dateTime to GMT time string using arbitrary format. + */ + Aws::String ToGmtString(const char* formatStr) const; + + /** + * Get the representation of this datetime as seconds.milliseconds since epoch + */ + double SecondsWithMSPrecision() const; + + /** + * Milliseconds since epoch of this datetime. + */ + int64_t Millis() const; + + /** + * In the likely case this class doesn't do everything you need to do, here's a copy of the time_point structure. Have fun. + */ + std::chrono::system_clock::time_point UnderlyingTimestamp() const; + + /** + * Get the Year portion of this dateTime. localTime if true, return local time, otherwise return UTC + */ + int GetYear(bool localTime = false) const; + + /** + * Get the Month portion of this dateTime. localTime if true, return local time, otherwise return UTC + */ + Month GetMonth(bool localTime = false) const; + + /** + * Get the Day of the Month portion of this dateTime. localTime if true, return local time, otherwise return UTC + */ + int GetDay(bool localTime = false) const; + + /** + * Get the Day of the Week portion of this dateTime. localTime if true, return local time, otherwise return UTC + */ + DayOfWeek GetDayOfWeek(bool localTime = false) const; + + /** + * Get the Hour portion of this dateTime. localTime if true, return local time, otherwise return UTC + */ + int GetHour(bool localTime = false) const; + + /** + * Get the Minute portion of this dateTime. localTime if true, return local time, otherwise return UTC + */ + int GetMinute(bool localTime = false) const; + + /** + * Get the Second portion of this dateTime. localTime if true, return local time, otherwise return UTC + */ + int GetSecond(bool localTime = false) const; + + /** + * Get whether or not this dateTime is in Daylight savings time. localTime if true, return local time, otherwise return UTC + */ + bool IsDST(bool localTime = false) const; + + /** + * Get an instance of DateTime representing this very instant. + */ + static DateTime Now(); + + /** + * Get the millis since epoch representing this very instant. + */ + static int64_t CurrentTimeMillis(); + + /** + * Calculates the current local timestamp, formats it and returns it as a string + */ + static Aws::String CalculateLocalTimestampAsString(const char* formatStr); + + /** + * Calculates the current gmt timestamp, formats it, and returns it as a string + */ + static Aws::String CalculateGmtTimestampAsString(const char* formatStr); + + /** + * Calculates the current hour of the day in localtime. + */ + static int CalculateCurrentHour(); + + /** + * The amazon timestamp format is a double with seconds.milliseconds + */ + static double ComputeCurrentTimestampInAmazonFormat(); + + /** + * Calculates the current time in GMT with millisecond precision using the format + * "Year-month-day hours:minutes:seconds.milliseconds" + */ + static Aws::String CalculateGmtTimeWithMsPrecision(); + + /** + * Compute the difference between two timestamps. + */ + static std::chrono::milliseconds Diff(const DateTime& a, const DateTime& b); + + std::chrono::milliseconds operator - (const DateTime& other) const; + private: + std::chrono::system_clock::time_point m_time; + bool m_valid; + + void ConvertTimestampStringToTimePoint(const char* timestamp, DateFormat format); + tm GetTimeStruct(bool localTime) const; + tm ConvertTimestampToLocalTimeStruct() const; + tm ConvertTimestampToGmtStruct() const; + }; + + } // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/EnumParseOverflowContainer.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/EnumParseOverflowContainer.h new file mode 100644 index 0000000000..0302e2bd36 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/EnumParseOverflowContainer.h @@ -0,0 +1,36 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/utils/memory/stl/AWSMap.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/threading/ReaderWriterLock.h> + +namespace Aws +{ + namespace Utils + { + /** + * This container is for storing unknown enum values that are encountered during parsing. + * This is to work around the round-tripping enums problem. It's really just a simple thread-safe + * hashmap. + */ + class AWS_CORE_API EnumParseOverflowContainer + { + public: + const Aws::String& RetrieveOverflow(int hashCode) const; + void StoreOverflow(int hashCode, const Aws::String& value); + + private: + mutable Aws::Utils::Threading::ReaderWriterLock m_overflowLock; + Aws::Map<int, Aws::String> m_overflowMap; + Aws::String m_emptyString; + }; + } +} + + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/FileSystemUtils.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/FileSystemUtils.h new file mode 100644 index 0000000000..d62ff4c094 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/FileSystemUtils.h @@ -0,0 +1,70 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/platform/FileSystem.h> + +#include <fstream> + +namespace Aws +{ + namespace Utils + { + + class AWS_CORE_API FStreamWithFileName : public Aws::FStream + { + public: + FStreamWithFileName(const Aws::String& fileName, std::ios_base::openmode openFlags) : + Aws::FStream(fileName.c_str(), openFlags), m_fileName(fileName) {} + + virtual ~FStreamWithFileName() = default; + + const Aws::String& GetFileName() const { return m_fileName; } + protected: + Aws::String m_fileName; + }; + + /** + * Provides a fstream around a temporary file. This file gets deleted upon an instance of this class's destructor being called. + */ + class AWS_CORE_API TempFile : public Aws::Utils::FStreamWithFileName + { + public: + /** + * Creates a temporary file with [prefix][temp name][suffix] e.g. + * prefix of "foo" and suffix of ".bar" will generate foo[some random string].bar + */ + TempFile(const char* prefix, const char* suffix, std::ios_base::openmode openFlags); + /** + * Creates a temporary file with [prefix][temp name] e.g. + * prefix of "foo" will generate foo[some random string] + */ + TempFile(const char* prefix, std::ios_base::openmode openFlags); + /** + * Creates a temporary file with a randome string for the name. + */ + TempFile(std::ios_base::openmode openFlags); + + ~TempFile(); + }; + + class AWS_CORE_API PathUtils + { + public: + + /** + * Get file name from it's full path, e.g get "file1" from "/path/to/file1.ext"; get "file2" from "/path/to/file2" + */ + static Aws::String GetFileNameFromPathWithoutExt(const Aws::String& path); + + /** + * Get file name from it's full path, e.g get "file1.ext" from "/path/to/file1.ext"; get "file2" from "/path/to/file2" + */ + static Aws::String GetFileNameFromPathWithExt(const Aws::String& path); + }; + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/GetTheLights.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/GetTheLights.h new file mode 100644 index 0000000000..f42475c8e4 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/GetTheLights.h @@ -0,0 +1,35 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSStack.h> +#include <functional> +#include <atomic> + +namespace Aws +{ + namespace Utils + { + /** + * Make initialization and cleanup of shared resources less painful. + * If you have this problem. Create a static instance of GetTheLights, + * have each actor call Enter the room with your callable. + * + * When you are finished with the shared resources call LeaveRoom(). The last caller will + * have its callable executed. + */ + class AWS_CORE_API GetTheLights + { + public: + GetTheLights(); + void EnterRoom(std::function<void()>&&); + void LeaveRoom(std::function<void()>&&); + private: + std::atomic<int> m_value; + }; + } +}
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/HashingUtils.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/HashingUtils.h new file mode 100644 index 0000000000..48c04daf59 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/HashingUtils.h @@ -0,0 +1,86 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/Array.h> + +namespace Aws +{ + namespace Utils + { + + /** + * Generic utils for hashing strings + */ + class AWS_CORE_API HashingUtils + { + public: + /** + * Base64 encodes string + */ + static Aws::String Base64Encode(const ByteBuffer& byteBuffer); + + /** + * Base64 decodes string + */ + static ByteBuffer Base64Decode(const Aws::String&); + + /** + * Hex encodes string + */ + static Aws::String HexEncode(const ByteBuffer& byteBuffer); + + /** + * Hex encodes string + */ + static ByteBuffer HexDecode(const Aws::String& str); + + /** + * Calculates a SHA256 HMAC digest (not hex encoded) + */ + static ByteBuffer CalculateSHA256HMAC(const ByteBuffer& toSign, const ByteBuffer& secret); + + /** + * Calculates a SHA256 Hash digest (not hex encoded) + */ + static ByteBuffer CalculateSHA256(const Aws::String& str); + + /** + * Calculates a SHA256 Hash digest on a stream (the entire stream is read, not hex encoded.) + */ + static ByteBuffer CalculateSHA256(Aws::IOStream& stream); + + /** + * Calculates a SHA256 Tree Hash digest (not hex encoded, see tree hash definition: http://docs.aws.amazon.com/amazonglacier/latest/dev/checksum-calculations.html) + */ + static ByteBuffer CalculateSHA256TreeHash(const Aws::String& str); + + /** + * Calculates a SHA256 Tree Hash digest on a stream (the entire stream is read, not hex encoded.) + */ + static ByteBuffer CalculateSHA256TreeHash(Aws::IOStream& stream); + + /** + * Calculates a MD5 Hash value + */ + static ByteBuffer CalculateMD5(const Aws::String& str); + + /** + * Calculates a MD5 Hash value + */ + static ByteBuffer CalculateMD5(Aws::IOStream& stream); + + static int HashString(const char* strToHash); + + }; + + } // namespace Utils +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/Outcome.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/Outcome.h new file mode 100644 index 0000000000..70e9e4be26 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/Outcome.h @@ -0,0 +1,170 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <cassert> +#include <utility> + +namespace Aws +{ + namespace Utils + { + + /** + * Template class representing the outcome of making a request. It will contain + * either a successful result or the failure error. The caller must check + * whether the outcome of the request was a success before attempting to access + * the result or the error. + */ + template<typename R, typename E> // Result, Error + class Outcome + { + public: + + Outcome() : result(), error(), success(false) + { + } + Outcome(const R& r) : result(r), error(), success(true) + { + } + Outcome(const E& e) : result(), error(e), success(false) + { + } + Outcome(R&& r) : result(std::forward<R>(r)), error(), success(true) + { + } + Outcome(E&& e) : result(), error(std::forward<E>(e)), success(false) + { + } + Outcome(const Outcome& o) : + result(o.result), + error(o.error), + success(o.success) + { + } + + template<typename RT, typename ET> + friend class Outcome; + +#if defined (__cplusplus) && __cplusplus > 201103L + template< bool B, class T = void > + using enable_if_t = std::enable_if_t<B, T>; +#else + template< bool B, class T = void > + using enable_if_t = typename std::enable_if<B,T>::type; +#endif + + // Move both result and error from other type of outcome + template<typename RT, typename ET, enable_if_t<std::is_convertible<RT, R>::value && + std::is_convertible<ET, E>::value, int> = 0> + Outcome(Outcome<RT, ET>&& o) : + result(std::move(o.result)), + error(std::move(o.error)), + success(o.success) + { + } + + // Move result from other type of outcome + template<typename RT, typename ET, enable_if_t<std::is_convertible<RT, R>::value && + !std::is_convertible<ET, E>::value, int> = 0> + Outcome(Outcome<RT, ET>&& o) : + result(std::move(o.result)), + success(o.success) + { + assert(o.success); + } + + // Move error from other type of outcome + template<typename RT, typename ET, enable_if_t<!std::is_convertible<RT, R>::value && + std::is_convertible<ET, E>::value, int> = 0> + Outcome(Outcome<RT, ET>&& o) : + error(std::move(o.error)), + success(o.success) + { + assert(!o.success); + } + + template<typename ET, enable_if_t<std::is_convertible<ET, E>::value, int> = 0> + Outcome(ET&& e) : error(std::forward<ET>(e)), success(false) + { + } + + Outcome& operator=(const Outcome& o) + { + if (this != &o) + { + result = o.result; + error = o.error; + success = o.success; + } + + return *this; + } + + Outcome(Outcome&& o) : // Required to force Move Constructor + result(std::move(o.result)), + error(std::move(o.error)), + success(o.success) + { + } + + Outcome& operator=(Outcome&& o) + { + if (this != &o) + { + result = std::move(o.result); + error = std::move(o.error); + success = o.success; + } + + return *this; + } + + inline const R& GetResult() const + { + return result; + } + + inline R& GetResult() + { + return result; + } + + /** + * casts the underlying result to an r-value so that caller can take ownership of underlying resources. + * this is necessary when streams are involved. + */ + inline R&& GetResultWithOwnership() + { + return std::move(result); + } + + inline const E& GetError() const + { + return error; + } + + template<typename T> + inline T GetError() + { + return error.template GetModeledError<T>(); + } + + inline bool IsSuccess() const + { + return this->success; + } + + private: + R result; + E error; + bool success; + }; + + } // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/ResourceManager.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/ResourceManager.h new file mode 100644 index 0000000000..517f65d0fa --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/ResourceManager.h @@ -0,0 +1,122 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include <aws/core/utils/memory/stl/AWSVector.h> +#include <mutex> +#include <condition_variable> +#include <atomic> +#include <cassert> + +namespace Aws +{ + namespace Utils + { + /** + * Generic resource manager with Acquire/Release semantics. Acquire will block waiting on a an available resource. Release will + * cause one blocked acquisition to unblock. + * + * You must call ShutdownAndWait() when finished with this container, this unblocks the listening thread and gives you a chance to + * clean up the resource if needed. + * After calling ShutdownAndWait(), you must not call Acquire any more. + */ + template< typename RESOURCE_TYPE> + class ExclusiveOwnershipResourceManager + { + public: + ExclusiveOwnershipResourceManager() : m_shutdown(false) {} + + /** + * Returns a resource with exclusive ownership. You must call Release on the resource when you are finished or other + * threads will block waiting to acquire it. + * + * @return instance of RESOURCE_TYPE + */ + RESOURCE_TYPE Acquire() + { + std::unique_lock<std::mutex> locker(m_queueLock); + while(!m_shutdown.load() && m_resources.size() == 0) + { + m_semaphore.wait(locker, [&](){ return m_shutdown.load() || m_resources.size() > 0; }); + } + + assert(!m_shutdown.load()); + + RESOURCE_TYPE resource = m_resources.back(); + m_resources.pop_back(); + + return resource; + } + + /** + * Returns whether or not resources are currently available for acquisition + * + * @return true means that at this instant some resources are available (though another thread may grab them from under you), + * this is only a hint. + */ + bool HasResourcesAvailable() + { + std::lock_guard<std::mutex> locker(m_queueLock); + return m_resources.size() > 0 && !m_shutdown.load(); + } + + /** + * Releases a resource back to the pool. This will unblock one waiting Acquire call if any are waiting. + * + * @param resource resource to release back to the pool + */ + void Release(RESOURCE_TYPE resource) + { + std::unique_lock<std::mutex> locker(m_queueLock); + m_resources.push_back(resource); + locker.unlock(); + m_semaphore.notify_one(); + } + + /** + * Does not block or even touch the semaphores. This is intended for setup only, do not use this after Acquire has been called for the first time. + * + * @param resource resource to be managed. + */ + void PutResource(RESOURCE_TYPE resource) + { + m_resources.push_back(resource); + } + + /** + * Waits for all acquired resources to be released, then empties the queue. + * You must call ShutdownAndWait() when finished with this container, this unblocks the listening thread and gives you a chance to + * clean up the resource if needed. + * After calling ShutdownAndWait(), you must not call Acquire any more. + * + * @params resourceCount the number of resources you've added to the resource manager. + * @return the previously managed resources that are now available for cleanup. + */ + Aws::Vector<RESOURCE_TYPE> ShutdownAndWait(size_t resourceCount) + { + Aws::Vector<RESOURCE_TYPE> resources; + std::unique_lock<std::mutex> locker(m_queueLock); + m_shutdown = true; + + //wait for all acquired resources to be released. + while (m_resources.size() < resourceCount) + { + m_semaphore.wait(locker, [&]() { return m_resources.size() == resourceCount; }); + } + + resources = m_resources; + m_resources.clear(); + + return resources; + } + + private: + Aws::Vector<RESOURCE_TYPE> m_resources; + std::mutex m_queueLock; + std::condition_variable m_semaphore; + std::atomic<bool> m_shutdown; + }; + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/StringUtils.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/StringUtils.h new file mode 100644 index 0000000000..312342b86a --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/StringUtils.h @@ -0,0 +1,219 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/memory/stl/AWSVector.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> + + + +namespace Aws +{ + namespace Utils + { + /** + * All the things the c++ stdlib is missing for string operations that I needed. + */ + class AWS_CORE_API StringUtils + { + public: + static void Replace(Aws::String& s, const char* search, const char* replace); + + + /** + * Converts a string to lower case. + */ + static Aws::String ToLower(const char* source); + + + /** + * Converts a string to upper case. + */ + static Aws::String ToUpper(const char* source); + + + /** + * Does a caseless comparison of two strings. + */ + static bool CaselessCompare(const char* value1, const char* value2); + + + /** + * URL encodes a string (uses %20 not + for spaces). + */ + static Aws::String URLEncode(const char* unsafe); + + /** + * Http Clients tend to escape some characters but not all. Escaping all of them causes problems, because the client + * will also try to escape them. + * So this only escapes non-ascii characters and the + character + */ + static Aws::String UTF8Escape(const char* unicodeString, const char* delimiter); + + /** + * URL encodes a double (if it ends up going to scientific notation) otherwise it just returns it as a string. + */ + static Aws::String URLEncode(double unsafe); + + + /** + * Decodes a URL encoded string (will handle both encoding schemes for spaces). + */ + static Aws::String URLDecode(const char* safe); + + enum class SplitOptions + { + /** + * By default, removes all the empty entries in the vector returned by Split() + */ + NOT_SET, + /** + * Includes empty entries in the vector returned by Split() + */ + INCLUDE_EMPTY_ENTRIES + }; + + /** + * @brief Splits a string on a delimiter (empty items are excluded). + * @param toSplit, the original string to split + * @param splitOn, the delemiter you want to use. + */ + static Aws::Vector<Aws::String> Split(const Aws::String& toSplit, char splitOn); + + /** + * @brief Splits a string on a delimiter. + * @param toSplit, the original string to split + * @param splitOn, the delemiter you want to use. + * @param option, if INCLUDE_EMPTY_ENTRIES, includes empty entries in the result, otherwise removes empty entries. + */ + static Aws::Vector<Aws::String> Split(const Aws::String& toSplit, char splitOn, SplitOptions option); + + /** + * @brief Splits a string on a delimiter (empty items are excluded). + * @param toSplit, the original string to split + * @param splitOn, the delemiter you want to use. + * @param numOfTargetParts, how many target parts you want to get, if it is 0, as many as possible. + */ + static Aws::Vector<Aws::String> Split(const Aws::String& toSplit, char splitOn, size_t numOfTargetParts); + + /** + * @brief Splits a string on a delimiter. + * @param toSplit, the original string to split + * @param splitOn, the delemiter you want to use. + * @param numOfTargetParts, how many target parts you want to get, if it is 0, as many as possible. + * @param option, if INCLUDE_EMPTY_ENTRIES, includes empty entries in the result, otherwise removes empty entries. + */ + static Aws::Vector<Aws::String> Split(const Aws::String& toSplit, char splitOn, size_t numOfTargetParts, SplitOptions option); + + /** + * Splits a string on new line characters. + */ + static Aws::Vector<Aws::String> SplitOnLine(const Aws::String& toSplit); + + + /** static Aws::Vector<Aws::String> SplitOnRegex(Aws::String regex); + * trim from start + */ + static Aws::String LTrim(const char* source); + + + /** + * trim from end + */ + static Aws::String RTrim(const char* source); + + /** + * trim from both ends + */ + static Aws::String Trim(const char* source); + + + /** + * convert to int 64 + */ + static long long ConvertToInt64(const char* source); + + + /** + * convert to int 32 + */ + static long ConvertToInt32(const char* source); + + + /** + * convert to bool + */ + static bool ConvertToBool(const char* source); + + + /** + * convert to double + */ + static double ConvertToDouble(const char* source); + + +#ifdef _WIN32 + /** + * Converts a string to wstring. + */ + static Aws::WString ToWString(const char* source); + + /** + * Converts a wstring to string. + */ + static Aws::String FromWString(const wchar_t* source); +#endif + + /** + * not all platforms (Android) have std::to_string + */ + template< typename T > + static Aws::String to_string(T value) + { + Aws::OStringStream os; + os << value; + return os.str(); + } + + /** + * locale agnostic implementation of std::isalnum + */ + static bool IsAlnum(char c) + { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'); + } + + /** + * Convert an unsigned integer to its hex string in upper case. + */ + template<typename T, class = typename std::enable_if<std::is_unsigned<T>::value>::type> + static Aws::String ToHexString(T value) + { + if (value == 0) + { + return "0"; + } + + Aws::String s; + s.reserve(sizeof(value) * 2); + T r = value; + while (r > 0) + { + s += "0123456789ABCDEF"[r & 0xf]; + r >>= 4; + } + + std::reverse(s.begin(), s.end()); + return s; + } + }; + + + } // namespace Utils +} // namespace Aws
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/UUID.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/UUID.h new file mode 100644 index 0000000000..e6320d14ef --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/UUID.h @@ -0,0 +1,52 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/Array.h> + +namespace Aws +{ + namespace Utils + { + static const size_t UUID_BINARY_SIZE = 0x10; + + /** + * Class encapsulating a UUID. This is platform dependent. The method you are most likely interested in is RandomUUID(). + */ + class AWS_CORE_API UUID + { + public: + /** + * Parses a GUID string into the raw data. + */ + UUID(const Aws::String&); + /** + * Sets the raw uuid data + */ + UUID(const unsigned char uuid[UUID_BINARY_SIZE]); + + /** + * Returns the current UUID as a GUID string + */ + operator Aws::String() const; + /** + * Returns a copy of the raw uuid + */ + inline operator ByteBuffer() const { return ByteBuffer(m_uuid, sizeof(m_uuid)); } + + /** + * Generates a UUID. It will always try to prefer a random implementation from the entropy source on the machine. If none, is available, it will + * fallback to the mac address and timestamp implementation. + */ + static UUID RandomUUID(); + + private: + unsigned char m_uuid[UUID_BINARY_SIZE]; + }; + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/UnreferencedParam.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/UnreferencedParam.h new file mode 100644 index 0000000000..d1bb74467d --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/UnreferencedParam.h @@ -0,0 +1,18 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +// taken from http://stackoverflow.com/questions/3020584/avoid-warning-unreferenced-formal-parameter, ugly but avoids having to #include the definition of an unreferenced struct/class + +#if defined (_MSC_VER) + + #define AWS_UNREFERENCED_PARAM(x) (&reinterpret_cast<const int &>(x)) + +#else + + #define AWS_UNREFERENCED_PARAM(x) ((void)(x)) + +#endif // _MSC_VER diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/base64/Base64.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/base64/Base64.h new file mode 100644 index 0000000000..454d20c262 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/base64/Base64.h @@ -0,0 +1,70 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#ifdef __APPLE__ + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif // __clang__ + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif // __GNUC__ + +#endif // __APPLE__ + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/Array.h> +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ + namespace Utils + { + namespace Base64 + { + + /** + * interface for platform specific Base64 encoding/decoding. + */ + class AWS_CORE_API Base64 + { + public: + Base64(const char *encodingTable = nullptr); + + /** + * Encode a byte buffer into a base64 stream. + * + * throws Base64Exception if encoding fails. + */ + Aws::String Encode(const ByteBuffer&) const; + + /** + * Decode a base64 string into a byte buffer. + */ + ByteBuffer Decode(const Aws::String&) const; + + /** + * Calculates the required length of a base64 buffer after decoding the + * input string. + */ + static size_t CalculateBase64DecodedLength(const Aws::String& b64input); + /** + * Calculates the length of an encoded base64 string based on the buffer being encoded + */ + static size_t CalculateBase64EncodedLength(const ByteBuffer& buffer); + + private: + char m_mimeBase64EncodingTable[64]; + uint8_t m_mimeBase64DecodingTable[256]; + + }; + + } // namespace Base64 + } // namespace Utils +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/Cipher.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/Cipher.h new file mode 100644 index 0000000000..fb31628b0e --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/Cipher.h @@ -0,0 +1,206 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/Array.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + static const size_t SYMMETRIC_KEY_LENGTH = 32; + static const size_t MIN_IV_LENGTH = 12; + + AWS_CORE_API CryptoBuffer IncrementCTRCounter(const CryptoBuffer& counter, uint32_t numberOfBlocks); + + /** + * Interface for symmetric encryption and decryption providers. An instance of this class is good for exactly one encryption or decryption run. + * It should not be used to encrypt or decrypt multiple messages. + */ + class AWS_CORE_API SymmetricCipher + { + public: + /** + * Initialize with key and an auto-generated initializationVector. Copies key. + * ivGenerationInCtrMode, if true, initializes the iv with a 4 byte counter at the end. + */ + SymmetricCipher(const CryptoBuffer& key, size_t ivSize, bool ivGenerationInCtrMode = false) : + m_key(key), + m_initializationVector(ivSize > 0 ? GenerateIV(ivSize, ivGenerationInCtrMode) : 0), + m_failure(false) + { + } + + /** + * Initialize with key and initializationVector, set tag for decryption of authenticated modes (makes copies of the buffers) + */ + SymmetricCipher(const CryptoBuffer& key, const CryptoBuffer& initializationVector, const CryptoBuffer& tag = CryptoBuffer(0)) : + m_key(key), + m_initializationVector(initializationVector), + m_tag(tag), + m_failure(false) + { + } + + /** + * Initialize with key and initializationVector, set tag for decryption of authenticated modes (move the buffers) + */ + SymmetricCipher(CryptoBuffer&& key, CryptoBuffer&& initializationVector, CryptoBuffer&& tag = CryptoBuffer(0)) : + m_key(std::move(key)), + m_initializationVector(std::move(initializationVector)), + m_tag(std::move(tag)), + m_failure(false) + { + } + + SymmetricCipher(const SymmetricCipher& other) = delete; + SymmetricCipher& operator=(const SymmetricCipher& other) = delete; + + /** + * Normally we don't work around VS 2013 not auto-generating these, but they are kind of expensive, + * so let's go ahead and optimize by defining default move operations. Implementors of this class + * need to be sure to define the move operations and call the base class. + */ + SymmetricCipher(SymmetricCipher&& toMove) : + m_key(std::move(toMove.m_key)), + m_initializationVector(std::move(toMove.m_initializationVector)), + m_tag(std::move(toMove.m_tag)), + m_failure(toMove.m_failure) + { + } + + /** + * Normally we don't work around VS 2013 not auto-generating these, but they are kind of expensive, + * so let's go ahead and optimize by defining default move operations. Implementors of this class + * need to be sure to define the move operations and call the base class. + */ + SymmetricCipher& operator=(SymmetricCipher&& toMove) + { + m_key = std::move(toMove.m_key); + m_initializationVector = std::move(toMove.m_initializationVector); + m_tag = std::move(toMove.m_tag); + m_failure = toMove.m_failure; + + return *this; + } + + virtual ~SymmetricCipher() = default; + + /** + * Whether or not the cipher is in a good state. If this ever returns false, throw away all buffers + * it has vended. + */ + virtual operator bool() const { return Good(); } + + /** + * Encrypt a buffer of data. Part of the contract for this interface is that intention that + * a user call this function multiple times for a large stream. As such, multiple calls to this function + * on the same instance should produce valid sequential output for an encrypted stream. + */ + virtual CryptoBuffer EncryptBuffer( const CryptoBuffer& unEncryptedData) = 0; + + /** + * Finalize Encryption, returns anything remaining in the last block + */ + virtual CryptoBuffer FinalizeEncryption () = 0; + + /** + * Decrypt a buffer of data. Part of the contract for this interface is that intention that + * a user call this function multiple times for a large stream. As such, multiple calls to this function + * on the same instance should produce valid sequential output from an encrypted stream. + */ + virtual CryptoBuffer DecryptBuffer(const CryptoBuffer& encryptedData) = 0; + + /** + * Finalize Decryption, returns anything remaining in the last block + */ + virtual CryptoBuffer FinalizeDecryption () = 0; + + virtual void Reset() = 0; + + /** + * IV used for encryption/decryption + */ + inline const CryptoBuffer& GetIV() const { return m_initializationVector; } + + /** + * Tag generated by encryption and used for the decryption. + * This will be set in an authenticated mode, otherwise empty + */ + inline const CryptoBuffer& GetTag() const { return m_tag; } + + inline bool Fail() const { return m_failure; } + inline bool Good() const { return !Fail(); } + + /** + * Generates a non-deterministic random IV. The first call is somewhat expensive but subsequent calls + * should be fast. If ctrMode is true, it will pad nonce in the first 1/4 of the iv and initialize + * the back 1/4 to 1. + */ + static CryptoBuffer GenerateIV(size_t ivLengthBytes, bool ctrMode = false); + + /** + * Generates a non-deterministic random symmetric key. Default (and minimum bar for security) is 256 bits. + */ + static CryptoBuffer GenerateKey(size_t keyLengthBytes = SYMMETRIC_KEY_LENGTH); + + protected: + + SymmetricCipher() : m_failure(false) {} + + CryptoBuffer m_key; + CryptoBuffer m_initializationVector; + CryptoBuffer m_tag; + bool m_failure; + }; + + /** + * Abstract factory class for Creating platform specific implementations of a Symmetric Cipher + */ + class SymmetricCipherFactory + { + public: + virtual ~SymmetricCipherFactory() {} + + /** + * Factory method. Returns cipher implementation. See the SymmetricCipher class for more details. + */ + virtual std::shared_ptr<SymmetricCipher> CreateImplementation(const CryptoBuffer& key) const = 0; + /** + * Factory method. Returns cipher implementation. See the SymmetricCipher class for more details. + */ + virtual std::shared_ptr<SymmetricCipher> CreateImplementation(const CryptoBuffer& key, const CryptoBuffer*) const + { + return CreateImplementation(key); + } + /** + * Factory method. Returns cipher implementation. See the SymmetricCipher class for more details. + */ + virtual std::shared_ptr<SymmetricCipher> CreateImplementation(const CryptoBuffer& key, const CryptoBuffer& iv, const CryptoBuffer& tag = CryptoBuffer(0), const CryptoBuffer& aad = CryptoBuffer(0)) const = 0; + /** + * Factory method. Returns cipher implementation. See the SymmetricCipher class for more details. + */ + virtual std::shared_ptr<SymmetricCipher> CreateImplementation(CryptoBuffer&& key, CryptoBuffer&& iv, CryptoBuffer&& tag = CryptoBuffer(0), CryptoBuffer&& aad = CryptoBuffer(0)) const = 0; + + /** + * Only called once per factory, your chance to make static library calls for setup. + * Default is no-op. + */ + virtual void InitStaticState() {} + + /** + * Only called once per factory, your chance to cleanup static library calls for setup. + * Default is no-op. + */ + virtual void CleanupStaticState() {} + }; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/ContentCryptoMaterial.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/ContentCryptoMaterial.h new file mode 100644 index 0000000000..ea99798853 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/ContentCryptoMaterial.h @@ -0,0 +1,244 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include <aws/core/Aws.h> +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/crypto/CryptoBuf.h> +#include <aws/core/utils/crypto/ContentCryptoScheme.h> +#include <aws/core/utils/crypto/KeyWrapAlgorithm.h> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + class AWS_CORE_API ContentCryptoMaterial + { + public: + /* + Default constructor. + */ + ContentCryptoMaterial(); + /* + Initialize content crypto material with content crypto scheme. Constructor will also generate the cek automatically. + Since the creation of the crypto content material will be within the S3 crypto modules, only the crypto scheme is needed for initialization. + The rest of the data will be set using the accessors below. + */ + ContentCryptoMaterial(ContentCryptoScheme contentCryptoScheme); + + /* + Initialize with content encryption key (cek) and content crypto scheme. + */ + ContentCryptoMaterial(const Aws::Utils::CryptoBuffer& cek, ContentCryptoScheme contentCryptoScheme); + + /** + * Gets the underlying content encryption key. + */ + inline const Aws::Utils::CryptoBuffer& GetContentEncryptionKey() const + { + return m_contentEncryptionKey; + } + + /** + * Gets the underlying encrypted content encryption key. + */ + inline const Aws::Utils::CryptoBuffer& GetEncryptedContentEncryptionKey() const + { + return m_encryptedContentEncryptionKey; + } + + /** + * Gets the underlying initialization vector + */ + inline const Aws::Utils::CryptoBuffer& GetIV() const + { + return m_iv; + } + + /** + * Gets the underlying crypto tag length + */ + inline size_t GetCryptoTagLength() const + { + return m_cryptoTagLength; + } + + /** + * Gets the underlying materials description map. + */ + inline const Aws::Map<Aws::String, Aws::String>& GetMaterialsDescription() const + { + return m_materialsDescription; + } + + /* + * Gets the value of the key in the current materials description map. + */ + inline const Aws::String& GetMaterialsDescription(const Aws::String& key) const + { + return m_materialsDescription.at(key); + } + + /** + * Gets the underlying key wrap algorithm + */ + inline KeyWrapAlgorithm GetKeyWrapAlgorithm() const + { + return m_keyWrapAlgorithm; + } + + /** + * Gets the underlying content crypto scheme. + */ + inline ContentCryptoScheme GetContentCryptoScheme() const + { + return m_contentCryptoScheme; + } + + /** + * Sets the underlying content encryption key. Copies from parameter content encryption key. + */ + inline void SetContentEncryptionKey(const Aws::Utils::CryptoBuffer& contentEncryptionKey) + { + m_contentEncryptionKey = contentEncryptionKey; + } + + /** + * Sets the underlying encrypted content encryption key. Copies from parameter encrypted content encryption key. + */ + inline void SetEncryptedContentEncryptionKey(const Aws::Utils::CryptoBuffer& encryptedContentEncryptionKey) + { + m_encryptedContentEncryptionKey = encryptedContentEncryptionKey; + } + + /** + * Sets the underlying iv. Copies from parameter iv. + */ + inline void SetIV(const Aws::Utils::CryptoBuffer& iv) + { + m_iv = iv; + } + + /** + * Sets the underlying crypto Tag Length. Copies from parameter cryptoTagLength. + */ + inline void SetCryptoTagLength(size_t cryptoTagLength) + { + m_cryptoTagLength = cryptoTagLength; + } + + /** + * Adds to the current materials description map using a key and a value. + */ + inline void AddMaterialsDescription(const Aws::String& key, const Aws::String& value) + { + m_materialsDescription[key] = value; + } + + /** + * Sets the underlying materials description. Copies from parameter materials description. + */ + inline void SetMaterialsDescription(const Aws::Map<Aws::String, Aws::String>& materialsDescription) + { + m_materialsDescription = materialsDescription; + } + + /** + * Sets the underlying Key Wrap Algorithm. Copies from parameter keyWrapAlgorithm. + */ + inline void SetKeyWrapAlgorithm(KeyWrapAlgorithm keyWrapAlgorithm) + { + m_keyWrapAlgorithm = keyWrapAlgorithm; + } + + /** + * Sets the underlying content Crypto Scheme. Copies from parameter contentCryptoScheme. + */ + inline void SetContentCryptoScheme(ContentCryptoScheme contentCryptoScheme) + { + m_contentCryptoScheme = contentCryptoScheme; + } + + /** + * Sets the underlying AAD for GCM if needed. + */ + inline void SetGCMAAD(const Aws::Utils::CryptoBuffer& aad) + { + m_gcmAAD = aad; + } + /** + * Gets the underlying aad for GCM if needed. + */ + inline const Aws::Utils::CryptoBuffer& GetGCMAAD() const + { + return m_gcmAAD; + } + + /** + * Sets the underlying tag for decrypting CEK if it's GCM encrypted. + */ + inline void SetCEKGCMTag(const Aws::Utils::CryptoBuffer& tag) + { + m_cekGCMTag = tag; + } + /** + * Gets the underlying aad for GCM if needed. + */ + inline const Aws::Utils::CryptoBuffer& GetCEKGCMTag() const + { + return m_cekGCMTag; + } + + /** + * Sets the underlying initialization vector for CEK if it's GCM encrypted. + */ + inline void SetCekIV(const Aws::Utils::CryptoBuffer& iv) + { + m_cekIV = iv; + } + /** + * Gets the underlying CEK initialization vector. + */ + inline const Aws::Utils::CryptoBuffer& GetCekIV() const + { + return m_cekIV; + } + + /** + * Sets the underlying final CEK + */ + inline void SetFinalCEK(const Aws::Utils::CryptoBuffer& finalCEK) + { + m_finalCEK = finalCEK; + } + /** + * Gets the underlying final CEK. + */ + inline const Aws::Utils::CryptoBuffer& GetFinalCEK() const + { + return m_finalCEK; + } + + private: + Aws::Utils::CryptoBuffer m_contentEncryptionKey; + Aws::Utils::CryptoBuffer m_encryptedContentEncryptionKey; + /* if using AES_GCM key wrap algorithm, then final CEK is iv + encrypted_key + tag + * otherwise it's the same as m_encryptedContentEncryptionKey + */ + Aws::Utils::CryptoBuffer m_finalCEK; + Aws::Utils::CryptoBuffer m_iv; + Aws::Utils::CryptoBuffer m_cekIV; + Aws::Utils::CryptoBuffer m_gcmAAD; + Aws::Utils::CryptoBuffer m_cekGCMTag; + size_t m_cryptoTagLength; + Aws::Map<Aws::String, Aws::String> m_materialsDescription; + KeyWrapAlgorithm m_keyWrapAlgorithm; + ContentCryptoScheme m_contentCryptoScheme; + }; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/ContentCryptoScheme.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/ContentCryptoScheme.h new file mode 100644 index 0000000000..605ad4e375 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/ContentCryptoScheme.h @@ -0,0 +1,32 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + enum class ContentCryptoScheme + { + CBC, + CTR, + GCM, + NONE + }; + + namespace ContentCryptoSchemeMapper + { + AWS_CORE_API ContentCryptoScheme GetContentCryptoSchemeForName(const Aws::String& name); + + AWS_CORE_API Aws::String GetNameForContentCryptoScheme(ContentCryptoScheme enumValue); + } + } //namespace Crypto + + }//namespace Utils +}//namespace Aws
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/CryptoBuf.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/CryptoBuf.h new file mode 100644 index 0000000000..1270c6b427 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/CryptoBuf.h @@ -0,0 +1,149 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include <aws/core/utils/crypto/Cipher.h> +#include <aws/core/Core_EXPORTS.h> +#include <ios> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + typedef std::mbstate_t FPOS_TYPE; + static const size_t DEFAULT_BUF_SIZE = 1024; + static const size_t PUT_BACK_SIZE = 1; + + /** + * Which mode a cipher is being used for. Encryption or Decryption + */ + enum class CipherMode + { + Encrypt, + Decrypt + }; + + /** + * Generic base class for a streambuf that handles cryptography. + */ + class AWS_CORE_API CryptoBuf : public std::streambuf + { + public: + CryptoBuf() = default; + virtual ~CryptoBuf() = default; + CryptoBuf(const CryptoBuf&) = delete; + CryptoBuf(CryptoBuf&& rhs) = delete; + /** + * If the buffer needs to do a final push to the sink or needs to empty the cipher blocks etc... + */ + virtual void Finalize() {} + }; + + /** + * StreamBuf that takes data from an input stream, encrypts or decrypts it, and causes all input received from the stream that is using it + * to go through the cipher. A common use case is a file that is encrypted on disk being read via ifstream and then read decrypted into memory. + * Or you could send a plain text file through an iostream and have it encrypted when the stream is read. + * + * This streambuf is seekable, but it is very expensive to seek backwards since we have to reset the cipher and re-encrypt everything up to that point. + * So seeking should be avoided if at all possible. + */ + class AWS_CORE_API SymmetricCryptoBufSrc : public CryptoBuf + { + public: + /** + * stream to src from + * cipher to encrypt or decrypt the src stream with + * mode to use cipher in. Encryption or Decryption + * buffersize, the size of the src buffers to read at a time. Defaults to 1kb + */ + SymmetricCryptoBufSrc(Aws::IStream& stream, SymmetricCipher& cipher, CipherMode cipherMode, size_t bufferSize = DEFAULT_BUF_SIZE); + + SymmetricCryptoBufSrc(const SymmetricCryptoBufSrc&) = delete; + SymmetricCryptoBufSrc(SymmetricCryptoBufSrc&&) = delete; + + SymmetricCryptoBufSrc& operator=(const SymmetricCryptoBufSrc&) = delete; + SymmetricCryptoBufSrc& operator=(SymmetricCryptoBufSrc&&) = delete; + + virtual ~SymmetricCryptoBufSrc() { FinalizeCipher(); } + + /** + * This call isn't necessary if you loop over the stream.read until you reach EOF, if you happen to read the exact + * amount as the in memory buffers and finish the stream, but never finish the finalize call you'll need to be sure + * to call this. This is automatically called by the destructor. + */ + void Finalize() override { FinalizeCipher(); } + + protected: + pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out ) override; + pos_type seekpos(pos_type pos, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out ) override; + + private: + int_type underflow() override; + off_type ComputeAbsSeekPosition(off_type, std::ios_base::seekdir, std::fpos<FPOS_TYPE>); + void FinalizeCipher(); + + CryptoBuffer m_isBuf; + SymmetricCipher& m_cipher; + Aws::IStream& m_stream; + CipherMode m_cipherMode; + bool m_isFinalized; + size_t m_bufferSize; + size_t m_putBack; + }; + + /** + * Stream buf that takes it's input, encrypts or decrypts it using the cipher, and writes it to the sink stream. This is particularly useful + * when receiving an encrypted file over the internet and writing it decrypted to disk. Another case may be that you have an ofstream and you want + * to write text to it from your program but have it go encrypted to disk. + * + * This stream buf is not seekable. + */ + class AWS_CORE_API SymmetricCryptoBufSink : public CryptoBuf + { + public: + /** + * stream, sink to push the encrypted or decrypted data to. + * cipher, symmetric cipher to use to transform the input before sending it to the sink. + * cipherMode, encrypt or decrypt + * bufferSize, amount of data to encrypt/decrypt at a time. + */ + SymmetricCryptoBufSink(Aws::OStream& stream, SymmetricCipher& cipher, CipherMode cipherMode, size_t bufferSize = DEFAULT_BUF_SIZE, int16_t blockOffset = 0); + SymmetricCryptoBufSink(const SymmetricCryptoBufSink&) = delete; + SymmetricCryptoBufSink(SymmetricCryptoBufSink&&) = delete; + + SymmetricCryptoBufSink& operator=(const SymmetricCryptoBufSink&) = delete; + /** + * Not move assignable since it contains reference members + */ + SymmetricCryptoBufSink& operator=(SymmetricCryptoBufSink&&) = delete; + + virtual ~SymmetricCryptoBufSink(); + + /** + * Finalizes the cipher and pushes all remaining data to the sink. Once this has been called, this streambuf cannot be used any further. + */ + void FinalizeCiphersAndFlushSink(); + /** + * Simply calls FinalizeCiphersAndFlushSink() + */ + void Finalize() override { FinalizeCiphersAndFlushSink(); } + + private: + int_type overflow(int_type ch) override; + int sync() override; + bool writeOutput(bool finalize); + + CryptoBuffer m_osBuf; + SymmetricCipher& m_cipher; + Aws::OStream& m_stream; + CipherMode m_cipherMode; + bool m_isFinalized; + int16_t m_blockOffset; + }; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/CryptoStream.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/CryptoStream.h new file mode 100644 index 0000000000..048d44392e --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/CryptoStream.h @@ -0,0 +1,81 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include <aws/core/utils/crypto/CryptoBuf.h> +#include <aws/core/Core_EXPORTS.h> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + /** + * IOStream that can either take a src buffer as an input stream and create a wrapper iostream that can be used to receive encrypted or decrypted + * input. + * + * A common use case is a file that is encrypted on disk being read via ifstream and then read decrypted into memory. + * Or you could send a plain text file through an iostream and have it encrypted when the stream is read. + * + * This stream is seekable, but it is very expensive to seek backwards since we have to reset the cipher and re-encrypt everything up to that point. + * So seeking should be avoided if at all possible. + * + * Or it can be used in the opposite direction where the stream is a sink and all input to the stream will be encrypted or decrypted and then sent to the + * sink stream. + * + * This is particularly useful + * when receiving an encrypted file over the internet and writing it decrypted to disk. Another case may be that you have an ofstream and you want + * to write text to it from your program but have it go encrypted to disk. + * + * In output mode, this stream is not seekable. + */ + class AWS_CORE_API SymmetricCryptoStream : public Aws::IOStream + { + public: + /** + * src stream to read from and encrypt or decrypt in transit + * mode of operation for cipher encryption or decryption + * cipher to use on the data + */ + SymmetricCryptoStream(Aws::IStream& src, CipherMode mode, SymmetricCipher& cipher, size_t bufLen = DEFAULT_BUF_SIZE); + /** + * sink stream to write the data to and encrypt or decrypt in transit + * mode of operation for cipher encryption or decryption + * cipher to use on the data + */ + SymmetricCryptoStream(Aws::OStream& sink, CipherMode mode, SymmetricCipher& cipher, size_t bufLen = DEFAULT_BUF_SIZE, int16_t blockOffset = 0 ); + /** + * bufSrc streambuf to use + */ + SymmetricCryptoStream(Aws::Utils::Crypto::SymmetricCryptoBufSrc& bufSrc); + /** + * bufSink streambuf to use + */ + SymmetricCryptoStream(Aws::Utils::Crypto::SymmetricCryptoBufSink& bufSink); + + SymmetricCryptoStream(const SymmetricCryptoStream&) = delete; + SymmetricCryptoStream(SymmetricCryptoStream&&) = delete; + + virtual ~SymmetricCryptoStream(); + + SymmetricCryptoStream& operator=(const SymmetricCryptoStream&) = delete; + SymmetricCryptoStream& operator=(SymmetricCryptoStream&&) = delete; + + + /** + * Call this in output stream mode when you want to flush the output to file. + * It will be called by the destructor, but if you want to sync before then, call this method. + * This stream is unusable after this method has been called. + */ + void Finalize(); + + private: + CryptoBuf* m_cryptoBuf; + bool m_hasOwnership; + }; + } + } +}
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/EncryptionMaterials.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/EncryptionMaterials.h new file mode 100644 index 0000000000..0fbc77c6b4 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/EncryptionMaterials.h @@ -0,0 +1,46 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/crypto/CryptoBuf.h> +#include <aws/core/utils/Outcome.h> +#include <aws/core/client/AWSError.h> +#include <aws/core/utils/crypto/ContentCryptoMaterial.h> +#include <aws/core/NoResult.h> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + enum class CryptoErrors + { + ENCRYPT_CONTENT_ENCRYPTION_KEY_FAILED, + DECRYPT_CONTENT_ENCRYPTION_KEY_FAILED, + GENERATE_CONTENT_ENCRYPTION_KEY_FAILED + }; + + typedef Outcome<Aws::NoResult, Aws::Client::AWSError<CryptoErrors>> CryptoOutcome; + + class AWS_CORE_API EncryptionMaterials + { + public: + virtual ~EncryptionMaterials(); + + /* + * Override this method to control how to encrypt the content encryption key (CEK). This occurs in place. + */ + virtual CryptoOutcome EncryptCEK(ContentCryptoMaterial& contentCryptoMaterial) = 0; + + /* + * Override this method to control how to decrypt the content encryption key (CEK). This occurs in place. + */ + virtual CryptoOutcome DecryptCEK(ContentCryptoMaterial& contentCryptoMaterial) = 0; + }; + }//namespace Crypto + }//namespace Utils +}//namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/Factories.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/Factories.h new file mode 100644 index 0000000000..b4c17b2a96 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/Factories.h @@ -0,0 +1,147 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/Array.h> +#include <memory> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + class Hash; + class HMAC; + class SymmetricCipher; + class HashFactory; + class HMACFactory; + class SymmetricCipherFactory; + class SecureRandomBytes; + class SecureRandomFactory; + + /** + * You need to call this before using any of the cryptography libs. Should be called after setting the factories. + */ + AWS_CORE_API void InitCrypto(); + /** + * You need to call this upon program shutdown. + */ + AWS_CORE_API void CleanupCrypto(); + /** + * OpenSSL infects everything with its global state. If it is being used then we automatically initialize and clean it up. + * If this is a problem for you, set this to false. Be aware that if you don't use our init and cleanup and you are using + * crypto functionality, you are responsible for installing thread locking, and loading strings and error messages. + */ + AWS_CORE_API void SetInitCleanupOpenSSLFlag(bool initCleanupFlag); + + /** + * Create an MD5 Hash provider + */ + AWS_CORE_API std::shared_ptr<Hash> CreateMD5Implementation(); + /** + * Create a Sha256 Hash provider + */ + AWS_CORE_API std::shared_ptr<Hash> CreateSha256Implementation(); + /** + * Create a Sha256 HMACHash provider + */ + AWS_CORE_API std::shared_ptr<HMAC> CreateSha256HMACImplementation(); + + /** + * Create AES in CBC mode off of a 256 bit key. Auto Generates a 16 byte secure random IV + */ + AWS_CORE_API std::shared_ptr<SymmetricCipher> CreateAES_CBCImplementation(const CryptoBuffer& key); + /** + * Create AES in CBC mode off of a 256 bit key and 16 byte IV + */ + AWS_CORE_API std::shared_ptr<SymmetricCipher> CreateAES_CBCImplementation(const CryptoBuffer& key, const CryptoBuffer& iv); + /** + * Create AES in CBC mode off of a 256 bit key and 16 byte IV + */ + AWS_CORE_API std::shared_ptr<SymmetricCipher> CreateAES_CBCImplementation(CryptoBuffer&& key, CryptoBuffer&& iv); + + /** + * Create AES in CTR mode off of a 256 bit key. Auto Generates a 16 byte IV in the format + * [nonce 4bytes ] [securely random iv 8 bytes] [ CTR init 4bytes ] + */ + AWS_CORE_API std::shared_ptr<SymmetricCipher> CreateAES_CTRImplementation(const CryptoBuffer& key); + /** + * Create AES in CTR mode off of a 256 bit key and 16 byte IV + */ + AWS_CORE_API std::shared_ptr<SymmetricCipher> CreateAES_CTRImplementation(const CryptoBuffer& key, const CryptoBuffer& iv); + /** + * Create AES in CTR mode off of a 256 bit key and 16 byte IV + */ + AWS_CORE_API std::shared_ptr<SymmetricCipher> CreateAES_CTRImplementation(CryptoBuffer&& key, CryptoBuffer&& iv); + + /** + * Create AES in GCM mode off of a 256 bit key. Auto Generates a 12 byte secure random IV. + */ + AWS_CORE_API std::shared_ptr<SymmetricCipher> CreateAES_GCMImplementation(const CryptoBuffer& key); + /** + * Create AES in GCM mode off of a 256 bit key. Auto Generates a 12 byte secure random IV and aad. + */ + AWS_CORE_API std::shared_ptr<SymmetricCipher> CreateAES_GCMImplementation(const CryptoBuffer& key, const CryptoBuffer* aad); + /** + * Create AES in GCM mode off of a 256 bit key, a 12 byte secure random IV, and an optional 16 byte Tag. If you are using this + * cipher to decrypt an encrypted payload, you must set the tag here. + */ + AWS_CORE_API std::shared_ptr<SymmetricCipher> CreateAES_GCMImplementation(const CryptoBuffer& key, const CryptoBuffer& iv, + const CryptoBuffer& tag = CryptoBuffer(0), const CryptoBuffer& aad = CryptoBuffer(0)); + /** + * Create AES in GCM mode off of a 256 bit key, a 16 byte secure random IV, and an optional 16 byte Tag, as well an optional add. If you are using this + * cipher to decrypt an encrypted payload, you must set the tag here. + */ + AWS_CORE_API std::shared_ptr<SymmetricCipher> CreateAES_GCMImplementation(CryptoBuffer&& key, CryptoBuffer&& iv, + CryptoBuffer&& tag = CryptoBuffer(0), CryptoBuffer&& aad = CryptoBuffer(0)); + /** + * Create AES in Key Wrap mode off of a 256 bit key. + */ + AWS_CORE_API std::shared_ptr<SymmetricCipher> CreateAES_KeyWrapImplementation(const CryptoBuffer& key); + + /** + * Create SecureRandomBytes instance + */ + AWS_CORE_API std::shared_ptr<SecureRandomBytes> CreateSecureRandomBytesImplementation(); + + /** + * Set the global factory for MD5 Hash providers + */ + AWS_CORE_API void SetMD5Factory(const std::shared_ptr<HashFactory>& factory); + /** + * Set the global factory for Sha256 Hash providers + */ + AWS_CORE_API void SetSha256Factory(const std::shared_ptr<HashFactory>& factory); + /** + * Set the global factory for Sha256 HMAC Hash providers + */ + AWS_CORE_API void SetSha256HMACFactory(const std::shared_ptr<HMACFactory>& factory); + /** + * Set the global factory for AES in CBC mode providers + */ + AWS_CORE_API void SetAES_CBCFactory(const std::shared_ptr<SymmetricCipherFactory>& factory); + /** + * Set the global factory for AES in CTR mode providers + */ + AWS_CORE_API void SetAES_CTRFactory(const std::shared_ptr<SymmetricCipherFactory>& factory); + /** + * Set the global factory for AES in GCM mode providers + */ + AWS_CORE_API void SetAES_GCMFactory(const std::shared_ptr<SymmetricCipherFactory>& factory); + /** + * Set the global factory for AES in Key Wrap mode providers + */ + AWS_CORE_API void SetAES_KeyWrapFactory(const std::shared_ptr<SymmetricCipherFactory>& factory); + /** + * Set the global factory for secure random bytes + */ + AWS_CORE_API void SetSecureRandomFactory(const std::shared_ptr<SecureRandomFactory>& factory); + + } // namespace Crypto + } // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/HMAC.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/HMAC.h new file mode 100644 index 0000000000..450997c736 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/HMAC.h @@ -0,0 +1,68 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + /* + * Interface for Sha256 encryptor and hmac + */ +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/Array.h> +#include <aws/core/utils/crypto/HashResult.h> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + /** + * Interface for HMAC hash providers. To implement an HMAC provider, inherit from this class and override Calculate. + */ + class AWS_CORE_API HMAC + { + public: + HMAC() {}; + virtual ~HMAC() {}; + + /** + * Calculates an HMAC digest + */ + virtual HashResult Calculate(const Aws::Utils::ByteBuffer& toSign, const Aws::Utils::ByteBuffer& secret) = 0; + + }; + + /** + * Simple abstract factory interface. Subclass this and create a factory if you want to control + * how HMAC Hash objects are created. + */ + class AWS_CORE_API HMACFactory + { + public: + virtual ~HMACFactory() {} + + /** + * Factory method. Returns hmac hash implementation. + */ + virtual std::shared_ptr<HMAC> CreateImplementation() const = 0; + + /** + * Opportunity to make any static initialization calls you need to make. + * Will only be called once. + */ + virtual void InitStaticState() {} + + /** + * Opportunity to make any static cleanup calls you need to make. + * will only be called at the end of the application. + */ + virtual void CleanupStaticState() {} + }; + + } // namespace Crypto + } // namespace Utils +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/Hash.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/Hash.h new file mode 100644 index 0000000000..8ebbe009fc --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/Hash.h @@ -0,0 +1,73 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/crypto/HashResult.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + /** + * Interface for computing hash codes using various hash algorithms + */ + class AWS_CORE_API Hash + { + public: + + Hash() {} + virtual ~Hash() {} + + /** + * Calculates a Hash digest + */ + virtual HashResult Calculate(const Aws::String& str) = 0; + + /** + * Calculates a Hash digest on a stream (the entire stream is read) + */ + virtual HashResult Calculate(Aws::IStream& stream) = 0; + + // when hashing streams, this is the size of our internal buffer we read the stream into + static const uint32_t INTERNAL_HASH_STREAM_BUFFER_SIZE = 8192; + }; + + /** + * Simple abstract factory interface. Subclass this and create a factory if you want to control + * how Hash objects are created. + */ + class AWS_CORE_API HashFactory + { + public: + virtual ~HashFactory() {} + + /** + * Factory method. Returns hash implementation. + */ + virtual std::shared_ptr<Hash> CreateImplementation() const = 0; + + /** + * Opportunity to make any static initialization calls you need to make. + * Will only be called once. + */ + virtual void InitStaticState() {} + + /** + * Opportunity to make any static cleanup calls you need to make. + * will only be called at the end of the application. + */ + virtual void CleanupStaticState() {} + }; + + } // namespace Crypto + } // namespace Utils +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/HashResult.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/HashResult.h new file mode 100644 index 0000000000..46b46d8095 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/HashResult.h @@ -0,0 +1,25 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/Array.h> + +namespace Aws +{ + namespace Utils + { + + template< typename R, typename E > class Outcome; + + namespace Crypto + { + using HashResult = Outcome< ByteBuffer, bool >; + + } // namespace Crypto + } // namespace Utils +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/KeyWrapAlgorithm.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/KeyWrapAlgorithm.h new file mode 100644 index 0000000000..0715f64740 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/KeyWrapAlgorithm.h @@ -0,0 +1,33 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + enum class KeyWrapAlgorithm + { + KMS, // Deprecated + KMS_CONTEXT, + AES_KEY_WRAP, // Deprecated + AES_GCM, + NONE + }; + + namespace KeyWrapAlgorithmMapper + { + AWS_CORE_API KeyWrapAlgorithm GetKeyWrapAlgorithmForName(const Aws::String& name); + + AWS_CORE_API Aws::String GetNameForKeyWrapAlgorithm(KeyWrapAlgorithm enumValue); + } + } //namespace Crypto + + }//namespace Utils +}//namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/MD5.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/MD5.h new file mode 100644 index 0000000000..59304a4a88 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/MD5.h @@ -0,0 +1,66 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + /* + * Interface for Sha256 encryptor and hmac + */ +#pragma once + +#ifdef __APPLE__ + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif // __clang__ + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif // __GNUC__ + +#endif // __APPLE__ + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/crypto/Hash.h> +#include <aws/core/utils/Outcome.h> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + class WindowsHashImpl; + + /** + * Md5 hash implementation + */ + class AWS_CORE_API MD5 : public Hash + { + public: + /** + * Initializes platform crypto libs for md5 + */ + MD5(); + virtual ~MD5(); + + /** + * Calculates an MD5 hash + */ + virtual HashResult Calculate(const Aws::String& str) override; + + /** + * Calculates a Hash digest on a stream (the entire stream is read) + */ + virtual HashResult Calculate(Aws::IStream& stream) override; + + private: + + std::shared_ptr<Hash> m_hashImpl; + }; + + } // namespace Crypto + } // namespace Utils +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/SecureRandom.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/SecureRandom.h new file mode 100644 index 0000000000..7f48dc008d --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/SecureRandom.h @@ -0,0 +1,116 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once +#include <type_traits> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + /** + * Interface for generating Random Bytes with guaranteed entropy for use with cryptographic functions. + * An instance is not guaranteed to be thread safe. This is intentional, that is needless overhead to + * pay for something you probably don't need. If you encounter a need for thread safety, you are responsible + * for memory fencing. + */ + class SecureRandomBytes + { + public: + SecureRandomBytes() : m_failure(false) + { + } + + virtual ~SecureRandomBytes() = default; + + /** + * fill in buffer of size bufferSize with random bytes + */ + virtual void GetBytes(unsigned char* buffer, size_t bufferSize) = 0; + + /** + * Always check this. If anything goes wrong, this tells you + */ + operator bool() const { return !m_failure; } + + protected: + bool m_failure; + }; + + /** + * Random Number generator for integral types. Guaranteed to have entropy or your program will crash. + */ + template <typename DataType = uint64_t> + class SecureRandom + { + public: + /** + * Initialize with the results of CreateSecureRandomBytesImplementation(). + * An instance is not guaranteed to be thread safe. This is intentional, that is needless overhead to + * pay for something you probably don't need. If you encounter a need for thread safety, you are responsible + * for memory fencing. + */ + SecureRandom(const std::shared_ptr<SecureRandomBytes>& entropySource) : m_entropy(entropySource) + { static_assert(std::is_unsigned<DataType>::value, "Type DataType must be integral"); } + + virtual ~SecureRandom() = default; + + virtual void Reset() {} + + /** + * Generate a random number of DataType + */ + virtual DataType operator()() + { + DataType value(0); + unsigned char buffer[sizeof(DataType)]; + m_entropy->GetBytes(buffer, sizeof(DataType)); + + assert(*m_entropy); + if(*m_entropy) + { + for (size_t i = 0; i < sizeof(DataType); ++i) + { + value <<= 8; + value |= buffer[i]; + + } + } + + return value; + } + + operator bool() const { return *m_entropy; } + + private: + std::shared_ptr<SecureRandomBytes> m_entropy; + }; + + class SecureRandomFactory + { + public: + virtual ~SecureRandomFactory() = default; + + /** + * Factory method. Returns SecureRandom implementation. + */ + virtual std::shared_ptr<SecureRandomBytes> CreateImplementation() const = 0; + + /** + * Opportunity to make any static initialization calls you need to make. + * Will only be called once. + */ + virtual void InitStaticState() {} + + /** + * Opportunity to make any static cleanup calls you need to make. + * will only be called at the end of the application. + */ + virtual void CleanupStaticState() {} + }; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/Sha256.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/Sha256.h new file mode 100644 index 0000000000..441752b0a6 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/Sha256.h @@ -0,0 +1,65 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + /* + * Interface for Sha256 encryptor and hmac + */ +#pragma once + +#ifdef __APPLE__ + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif // __clang__ + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif // __GNUC__ + +#endif // __APPLE__ + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/crypto/Hash.h> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + class WindowsHashImpl; + + /** + * Sha256 hash implementation. + */ + class AWS_CORE_API Sha256 : public Hash + { + public: + /** + * Initializes platform crypto libs. + */ + Sha256(); + virtual ~Sha256(); + + /** + * Calculates a SHA256 Hash digest (not hex encoded) + */ + virtual HashResult Calculate(const Aws::String& str) override; + + /** + * Calculates a Hash digest on a stream (the entire stream is read) + */ + virtual HashResult Calculate(Aws::IStream& stream) override; + + private: + + std::shared_ptr< Hash > m_hashImpl; + }; + + } // namespace Crypto + } // namespace Utils +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/Sha256HMAC.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/Sha256HMAC.h new file mode 100644 index 0000000000..d035b99da5 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/Sha256HMAC.h @@ -0,0 +1,59 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + /* + * Interface for Sha256 encryptor and hmac + */ +#pragma once + +#ifdef __APPLE__ + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif // __clang__ + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif // __GNUC__ + +#endif // __APPLE__ + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/crypto/HMAC.h> +#include <aws/core/utils/memory/AWSMemory.h> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + /** + * Sha256 HMAC implementation + */ + class AWS_CORE_API Sha256HMAC : public HMAC + { + public: + /** + * initializes platform specific libs. + */ + Sha256HMAC(); + virtual ~Sha256HMAC(); + + /** + * Calculates a SHA256 HMAC digest (not hex encoded) + */ + virtual HashResult Calculate(const Aws::Utils::ByteBuffer& toSign, const Aws::Utils::ByteBuffer& secret) override; + + private: + + std::shared_ptr< HMAC > m_hmacImpl; + }; + + } // namespace Sha256 + } // namespace Utils +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/openssl/CryptoImpl.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/openssl/CryptoImpl.h new file mode 100644 index 0000000000..e3f37edda9 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/crypto/openssl/CryptoImpl.h @@ -0,0 +1,371 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include <aws/core/utils/crypto/Hash.h> +#include <aws/core/utils/crypto/HMAC.h> +#include <aws/core/utils/crypto/Cipher.h> +#include <aws/core/utils/crypto/SecureRandom.h> +#include <aws/core/utils/GetTheLights.h> +#include <openssl/ossl_typ.h> +#include <openssl/evp.h> +#include <openssl/hmac.h> +#include <openssl/rand.h> +#include <atomic> +#include <mutex> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + namespace OpenSSL + { + extern GetTheLights getTheLights; + + void init_static_state(); + + void cleanup_static_state(); + + void locking_fn(int mode, int n, const char* file, int line); + + unsigned long id_fn(); + } + + /** + * OpenSSL implementation for SecureRandomBytes. + * Incidentally, this implementation is thread safe, though it is not + * on other platforms. You should treat an instance of SecureRandomBytes + * as needed to be memory fenced if you will be using accross multiple threads + */ + class SecureRandomBytes_OpenSSLImpl : public SecureRandomBytes + { + public: + SecureRandomBytes_OpenSSLImpl() + { } + + ~SecureRandomBytes_OpenSSLImpl() = default; + + /** + * Reads bufferSize bytes from RAND_bytes into buffer. + */ + void GetBytes(unsigned char* buffer, size_t bufferSize) override; + }; + + class MD5OpenSSLImpl : public Hash + { + public: + + MD5OpenSSLImpl() + { } + + virtual ~MD5OpenSSLImpl() = default; + + virtual HashResult Calculate(const Aws::String& str) override; + + virtual HashResult Calculate(Aws::IStream& stream) override; + + }; + + class Sha256OpenSSLImpl : public Hash + { + public: + Sha256OpenSSLImpl() + { } + + virtual ~Sha256OpenSSLImpl() = default; + + virtual HashResult Calculate(const Aws::String& str) override; + + virtual HashResult Calculate(Aws::IStream& stream) override; + }; + + class Sha256HMACOpenSSLImpl : public HMAC + { + public: + virtual ~Sha256HMACOpenSSLImpl() = default; + + virtual HashResult Calculate(const ByteBuffer& toSign, const ByteBuffer& secret) override; + }; + + /** + * OpenSSL implementation for SymmetricCipher + */ + class OpenSSLCipher : public SymmetricCipher + { + public: + /** + * Creates new OpenSSL based cipher for key, and autogenerates a secure IV of size ivSize + */ + OpenSSLCipher(const CryptoBuffer& key, size_t ivSize, bool ctrMode = false); + + /** + * Creates new OpenSSL based cipher for key, initializationVector, and optional tag. If this is an authenticated + * cipher being used for decryption. + */ + OpenSSLCipher(CryptoBuffer&& key, CryptoBuffer&& initializationVector, + CryptoBuffer&& tag = CryptoBuffer(0)); + + /** + * Creates new OpenSSL based cipher for key, initializationVector, and optional tag. If this is an authenticated + * cipher being used for decryption. + */ + OpenSSLCipher(const CryptoBuffer& key, const CryptoBuffer& initializationVector, + const CryptoBuffer& tag = CryptoBuffer(0)); + + OpenSSLCipher(const OpenSSLCipher& other) = delete; + + OpenSSLCipher& operator=(const OpenSSLCipher& other) = delete; + + /** + * Normally we don't work around VS 2013 not auto-generating these, but they are kind of expensive, + * so let's go ahead and optimize by defining default move operations. Implementors of this class + * need to be sure to define the move operations and call the base class. + */ + OpenSSLCipher(OpenSSLCipher&& toMove); + + /** + * Normally we don't work around VS 2013 not auto-generating these, but they are kind of expensive, + * so let's go ahead and optimize by defining default move operations. Implementors of this class + * need to be sure to define the move operations and call the base class. + */ + OpenSSLCipher& operator=(OpenSSLCipher&& toMove) = default; + + + virtual ~OpenSSLCipher(); + + /** + * Encrypt a buffer of data. Part of the contract for this interface is that intention that + * a user call this function multiple times for a large stream. As such, multiple calls to this function + * on the same instance should produce valid sequential output for an encrypted stream. + */ + CryptoBuffer EncryptBuffer(const CryptoBuffer& unEncryptedData) override; + + /** + * Finalize Encryption, returns anything remaining in the last block + */ + CryptoBuffer FinalizeEncryption() override; + + /** + * Decrypt a buffer of data. Part of the contract for this interface is that intention that + * a user call this function multiple times for a large stream. As such, multiple calls to this function + * on the same instance should produce valid sequential output from an encrypted stream. + */ + CryptoBuffer DecryptBuffer(const CryptoBuffer& encryptedData) override; + + /** + * Finalize Decryption, returns anything remaining in the last block + */ + CryptoBuffer FinalizeDecryption() override; + + void Reset() override; + + protected: + virtual size_t GetBlockSizeBytes() const = 0; + virtual size_t GetKeyLengthBits() const = 0; + bool CheckKeyAndIVLength(size_t expectedKeyLength, size_t expectedIVLength); + + EVP_CIPHER_CTX* m_encryptor_ctx; + EVP_CIPHER_CTX* m_decryptor_ctx; + private: + void Init(); + void Cleanup(); + + /* openssl has bug finalize decryption of an empty string */ + bool m_emptyPlaintext; + }; + + /** + * OpenSSL implementation for AES in CBC mode + */ + class AES_CBC_Cipher_OpenSSL : public OpenSSLCipher + { + public: + /** + * Create AES in CBC mode off of a 256 bit key. Auto Generates a 16 byte secure random IV + */ + AES_CBC_Cipher_OpenSSL(const CryptoBuffer& key); + + /** + * Create AES in CBC mode off of a 256 bit key and 16 byte IV + */ + AES_CBC_Cipher_OpenSSL(CryptoBuffer&& key, CryptoBuffer&& initializationVector); + + /** + * Create AES in CBC mode off of a 256 bit key and 16 byte IV + */ + AES_CBC_Cipher_OpenSSL(const CryptoBuffer& key, const CryptoBuffer& initializationVector); + + AES_CBC_Cipher_OpenSSL(const AES_CBC_Cipher_OpenSSL& other) = delete; + + AES_CBC_Cipher_OpenSSL& operator=(const AES_CBC_Cipher_OpenSSL& other) = delete; + + AES_CBC_Cipher_OpenSSL(AES_CBC_Cipher_OpenSSL&& toMove) = default; + + void Reset() override; + + protected: + size_t GetBlockSizeBytes() const override; + + size_t GetKeyLengthBits() const override; + + private: + void InitCipher(); + + static size_t BlockSizeBytes; + static size_t KeyLengthBits; + }; + + /** + * OpenSSL implementation for AES in CTR mode + */ + class AES_CTR_Cipher_OpenSSL : public OpenSSLCipher + { + public: + /** + * Create AES in CTR mode off of a 256 bit key. Auto Generates a 16 byte IV in the format + * [nonce 4bytes ] [securely random iv 8 bytes] [ CTR init 4bytes ] + */ + AES_CTR_Cipher_OpenSSL(const CryptoBuffer& key); + + /** + * Create AES in CTR mode off of a 256 bit key and 16 byte IV + */ + AES_CTR_Cipher_OpenSSL(CryptoBuffer&& key, CryptoBuffer&& initializationVector); + + /** + * Create AES in CTR mode off of a 256 bit key and 16 byte IV + */ + AES_CTR_Cipher_OpenSSL(const CryptoBuffer& key, const CryptoBuffer& initializationVector); + + AES_CTR_Cipher_OpenSSL(const AES_CTR_Cipher_OpenSSL& other) = delete; + + AES_CTR_Cipher_OpenSSL& operator=(const AES_CTR_Cipher_OpenSSL& other) = delete; + + AES_CTR_Cipher_OpenSSL(AES_CTR_Cipher_OpenSSL&& toMove) = default; + + void Reset() override; + + protected: + size_t GetBlockSizeBytes() const override; + + size_t GetKeyLengthBits() const override; + + private: + void InitCipher(); + + static size_t BlockSizeBytes; + static size_t KeyLengthBits; + }; + + /** + * OpenSSL implementation for AES in GCM mode + */ + class AES_GCM_Cipher_OpenSSL : public OpenSSLCipher + { + public: + /** + * Create AES in GCM mode off of a 256 bit key. Auto Generates a 12 byte secure random IV. + */ + AES_GCM_Cipher_OpenSSL(const CryptoBuffer& key); + + /** + * Create AES in GCM mode off of a 256 bit key and AAD. Auto Generates a 12 byte IV in the format + */ + AES_GCM_Cipher_OpenSSL(const CryptoBuffer& key, const CryptoBuffer* aad); + + /** + * Create AES in GCM mode off of a 256 bit key, a 12 byte secure random IV, and an optional 16 byte Tag and additional authentication data (AAD). + * Note that tag could be acquired from encrypt mode and should only be set for decrypt mode. + * If you are using this cipher to decrypt an encrypted payload, you must set the tag here. + */ + AES_GCM_Cipher_OpenSSL(CryptoBuffer&& key, CryptoBuffer&& initializationVector, + CryptoBuffer&& tag = CryptoBuffer(0), CryptoBuffer&& aad = CryptoBuffer(0)); + + /** + * Create AES in GCM mode off of a 256 bit key, a 12 byte secure random IV, and an optional 16 byte Tag and additional authentication data (AAD). + * Note that tag could be acquired from encrypt mode and should only be set for decrypt mode. + * If you are using this cipher to decrypt an encrypted payload, you must set the tag here. + */ + AES_GCM_Cipher_OpenSSL(const CryptoBuffer& key, const CryptoBuffer& initializationVector, + const CryptoBuffer& tag = CryptoBuffer(0), const CryptoBuffer& aad = CryptoBuffer(0)); + + AES_GCM_Cipher_OpenSSL(const AES_GCM_Cipher_OpenSSL& other) = delete; + + AES_GCM_Cipher_OpenSSL& operator=(const AES_GCM_Cipher_OpenSSL& other) = delete; + + AES_GCM_Cipher_OpenSSL(AES_GCM_Cipher_OpenSSL&& toMove) = default; + + /** + * Calls base class first, then grabs the tag from the cipher and sets it on m_tag. + * After calling FinalizeEncryption, be sure to call GetTag() and do something with it + * or you will not be able to decrypt the payload. + */ + CryptoBuffer FinalizeEncryption() override; + + void Reset() override; + + protected: + size_t GetBlockSizeBytes() const override; + + size_t GetKeyLengthBits() const override; + + size_t GetTagLengthBytes() const; + + private: + void InitCipher(); + + CryptoBuffer m_aad; + static size_t BlockSizeBytes; + static size_t IVLengthBytes; + static size_t KeyLengthBits; + static size_t TagLengthBytes; + }; + + /** + * OpenSSL implementation for AES in Key Wrap mode. The key for the c_tor is the Kek, + * it either encrypts a CEK or decrypts it. + */ + class AES_KeyWrap_Cipher_OpenSSL : public OpenSSLCipher + { + public: + + /** + * Create AES in Key Wrap mode off of a 256 bit key. + */ + AES_KeyWrap_Cipher_OpenSSL(const CryptoBuffer& key); + + AES_KeyWrap_Cipher_OpenSSL(const AES_KeyWrap_Cipher_OpenSSL&) = delete; + + AES_KeyWrap_Cipher_OpenSSL& operator=(const AES_KeyWrap_Cipher_OpenSSL&) = delete; + + AES_KeyWrap_Cipher_OpenSSL(AES_KeyWrap_Cipher_OpenSSL&&) = default; + + CryptoBuffer EncryptBuffer(const CryptoBuffer&) override; + CryptoBuffer FinalizeEncryption() override; + + CryptoBuffer DecryptBuffer(const CryptoBuffer&) override; + CryptoBuffer FinalizeDecryption() override; + + void Reset() override; + + protected: + inline size_t GetBlockSizeBytes() const override { return BlockSizeBytes; } + + inline size_t GetKeyLengthBits() const override { return KeyLengthBits; } + + private: + void InitCipher(); + + static size_t BlockSizeBytes; + static size_t KeyLengthBits; + + CryptoBuffer m_workingKeyBuffer; + }; + + } // namespace Crypto + } // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventDecoderStream.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventDecoderStream.h new file mode 100644 index 0000000000..81a8f92eb9 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventDecoderStream.h @@ -0,0 +1,43 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/event/EventStreamBuf.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> + +namespace Aws +{ + namespace Utils + { + namespace Event + { + extern AWS_CORE_API const size_t DEFAULT_BUF_SIZE; + + /** + * A buffered I/O stream that binary-decodes the bits written to it according to the AWS event-stream spec. + * The decoding process will result in invoking callbacks on the handler assigned to the decoder parameter. + */ + class AWS_CORE_API EventDecoderStream : public Aws::IOStream + { + public: + /** + * Creates a stream for decoding events sent by the service. + * @param decoder decodes the stream from server side, so as to invoke related callback functions. + * @param eventStreamBufLength The length of the underlying buffer. + */ + EventDecoderStream(EventStreamDecoder& decoder, size_t bufferSize = DEFAULT_BUF_SIZE); + + private: + EventDecoderStream(const EventDecoderStream&) = delete; + EventDecoderStream(EventDecoderStream&&) = delete; + EventDecoderStream& operator=(const EventDecoderStream&) = delete; + EventDecoderStream& operator=(EventDecoderStream&&) = delete; + + EventStreamBuf m_eventStreamBuf; + }; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventEncoderStream.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventEncoderStream.h new file mode 100644 index 0000000000..19cf2a5874 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventEncoderStream.h @@ -0,0 +1,69 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/stream/ConcurrentStreamBuf.h> +#include <aws/core/utils/event/EventMessage.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/utils/event/EventStreamEncoder.h> + +namespace Aws +{ + namespace Client + { + class AWSAuthSigner; + } + + namespace Utils + { + namespace Event + { + extern AWS_CORE_API const size_t DEFAULT_BUF_SIZE; + + /** + * A buffered I/O stream that binary-encodes the bits written to it according to the AWS event-stream spec. + */ + class AWS_CORE_API EventEncoderStream : public Aws::IOStream + { + public: + + /** + * Creates a stream for encoding events sent by the client. + * @param bufferSize The length of the underlying buffer. + */ + explicit EventEncoderStream(size_t bufferSize = DEFAULT_BUF_SIZE); + + /** + * Sets the signature seed used by event-stream events. + * Every event uses its previous event's signature to calculate its own signature. + * Setting this value affects the signature calculation of the first event. + */ + void SetSignatureSeed(const Aws::String& seed) { m_encoder.SetSignatureSeed(seed); } + + /** + * Writes an event-stream message to the underlying buffer. + */ + EventEncoderStream& WriteEvent(const Aws::Utils::Event::Message& msg); + + /** + * Sets the signer implementation used for every event. + */ + void SetSigner(Aws::Client::AWSAuthSigner* signer) { m_encoder.SetSigner(signer); } + + /** + * Allows a stream writer to communicate the end of the stream to a stream reader. + * + * Any writes to the stream after this call are not guaranteed to be read by another concurrent + * read thread. + */ + void Close() { m_streambuf.SetEof(); setstate(eofbit); } + + private: + Stream::ConcurrentStreamBuf m_streambuf; + EventStreamEncoder m_encoder; + }; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventHeader.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventHeader.h new file mode 100644 index 0000000000..c60dda0435 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventHeader.h @@ -0,0 +1,311 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/Array.h> +#include <aws/core/utils/memory/stl/AWSMap.h> +#include <aws/core/utils/UUID.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/event-stream/event_stream.h> +#include <cassert> + +namespace Aws +{ + namespace Utils + { + namespace Event + { + static const char CLASS_TAG[] = "EventHeader"; + /** + * Interface of the header value of a message in event stream. + * Each type of header value should have it's own associated derived class based on this class. + */ + class AWS_CORE_API EventHeaderValue + { + public: + enum class EventHeaderType + { + BOOL_TRUE = 0, + BOOL_FALSE, + BYTE, + INT16, + INT32, + INT64, + BYTE_BUF, + STRING, + /* 64 bit integer (millis since epoch) */ + TIMESTAMP, + UUID, + UNKNOWN + }; + + EventHeaderValue() = default; + + EventHeaderValue(aws_event_stream_header_value_pair* header) : + m_eventHeaderType(static_cast<EventHeaderType>(header->header_value_type)) + { + switch (m_eventHeaderType) + { + case EventHeaderType::BOOL_TRUE: + case EventHeaderType::BOOL_FALSE: + m_eventHeaderStaticValue.boolValue = aws_event_stream_header_value_as_bool(header) != 0; + break; + case EventHeaderType::BYTE: + m_eventHeaderStaticValue.byteValue = aws_event_stream_header_value_as_byte(header); + break; + case EventHeaderType::INT16: + m_eventHeaderStaticValue.int16Value = aws_event_stream_header_value_as_int16(header); + break; + case EventHeaderType::INT32: + m_eventHeaderStaticValue.int32Value = aws_event_stream_header_value_as_int32(header); + break; + case EventHeaderType::INT64: + m_eventHeaderStaticValue.int64Value = aws_event_stream_header_value_as_int64(header); + break; + case EventHeaderType::BYTE_BUF: + m_eventHeaderVariableLengthValue = ByteBuffer(static_cast<uint8_t*>(aws_event_stream_header_value_as_bytebuf(header).buffer), header->header_value_len); + break; + case EventHeaderType::STRING: + m_eventHeaderVariableLengthValue = ByteBuffer(static_cast<uint8_t*>(aws_event_stream_header_value_as_string(header).buffer), header->header_value_len); + break; + case EventHeaderType::TIMESTAMP: + m_eventHeaderStaticValue.timestampValue = aws_event_stream_header_value_as_timestamp(header); + break; + case EventHeaderType::UUID: + assert(header->header_value_len == 16u); + m_eventHeaderVariableLengthValue = ByteBuffer(static_cast<uint8_t*>(aws_event_stream_header_value_as_uuid(header).buffer), header->header_value_len); + break; + default: + AWS_LOG_ERROR(CLASS_TAG, "Encountered unknown type of header."); + break; + } + }; + + EventHeaderValue(const Aws::String& s) : + m_eventHeaderType(EventHeaderType::STRING), + m_eventHeaderVariableLengthValue(reinterpret_cast<const uint8_t*>(s.data()), s.length()) + { + } + + EventHeaderValue(const ByteBuffer& bb) : + m_eventHeaderType(EventHeaderType::BYTE_BUF), + m_eventHeaderVariableLengthValue(bb) + { + } + + EventHeaderValue(ByteBuffer&& bb) : + m_eventHeaderType(EventHeaderType::BYTE_BUF), + m_eventHeaderVariableLengthValue(std::move(bb)) + { + } + + + explicit EventHeaderValue(unsigned char byte) : + m_eventHeaderType(EventHeaderType::BYTE) + { + m_eventHeaderStaticValue.byteValue = byte; + } + + explicit EventHeaderValue(bool b) : + m_eventHeaderType(b ? EventHeaderType::BOOL_TRUE : EventHeaderType::BOOL_FALSE) + { + m_eventHeaderStaticValue.boolValue = b; + } + + explicit EventHeaderValue(int16_t n) : + m_eventHeaderType(EventHeaderType::INT16) + { + m_eventHeaderStaticValue.int16Value = n; + } + + explicit EventHeaderValue(int32_t n) : + m_eventHeaderType(EventHeaderType::INT32) + { + m_eventHeaderStaticValue.int32Value = n; + } + + explicit EventHeaderValue(int64_t n, EventHeaderType type = EventHeaderType::INT64) : + m_eventHeaderType(type) + { + if (type == EventHeaderType::TIMESTAMP) + { + m_eventHeaderStaticValue.timestampValue = n; + } + else + { + m_eventHeaderStaticValue.int64Value = n; + } + } + + EventHeaderType GetType() const { return m_eventHeaderType; } + + + static EventHeaderType GetEventHeaderTypeForName(const Aws::String& name); + static Aws::String GetNameForEventHeaderType(EventHeaderType value); + + /** + * Get header value as boolean. + * Log error if derived class doesn't override this function. + */ + inline bool GetEventHeaderValueAsBoolean() const + { + assert(m_eventHeaderType == EventHeaderType::BOOL_TRUE || m_eventHeaderType == EventHeaderType::BOOL_FALSE); + if (m_eventHeaderType != EventHeaderType::BOOL_TRUE && m_eventHeaderType != EventHeaderType::BOOL_FALSE) + { + AWS_LOGSTREAM_ERROR(CLASS_TAG, "Expected event header type is TRUE or FALSE, but encountered " << GetNameForEventHeaderType(m_eventHeaderType)); + return false; + } + return m_eventHeaderStaticValue.boolValue; + } + + /** + * Get header value as byte. + * Log error if derived class doesn't override this function. + */ + inline uint8_t GetEventHeaderValueAsByte() const + { + assert(m_eventHeaderType == EventHeaderType::BYTE); + if (m_eventHeaderType != EventHeaderType::BYTE) + { + AWS_LOGSTREAM_ERROR(CLASS_TAG, "Expected event header type is BYTE, but encountered " << GetNameForEventHeaderType(m_eventHeaderType)); + return static_cast<uint8_t>(0); + } + return m_eventHeaderStaticValue.byteValue; + } + + /** + * Get header value as 16 bit integer. + * Log error if derived class doesn't override this function. + */ + inline int16_t GetEventHeaderValueAsInt16() const + { + assert(m_eventHeaderType == EventHeaderType::INT16); + if (m_eventHeaderType != EventHeaderType::INT16) + { + AWS_LOGSTREAM_ERROR(CLASS_TAG, "Expected event header type is INT16, but encountered " << GetNameForEventHeaderType(m_eventHeaderType)); + return static_cast<int16_t>(0); + } + return m_eventHeaderStaticValue.int16Value; + } + + /** + * Get header value as 32 bit integer. + * Log error if derived class doesn't override this function. + */ + inline int32_t GetEventHeaderValueAsInt32() const + { + assert(m_eventHeaderType == EventHeaderType::INT32); + if (m_eventHeaderType != EventHeaderType::INT32) + { + AWS_LOGSTREAM_ERROR(CLASS_TAG, "Expected event header type is INT32, but encountered " << GetNameForEventHeaderType(m_eventHeaderType)); + return static_cast<int32_t>(0); + } + return m_eventHeaderStaticValue.int32Value; + } + + /** + * Get header value as 64 bit integer. + * Log error if derived class doesn't override this function. + */ + inline int64_t GetEventHeaderValueAsInt64() const + { + assert(m_eventHeaderType == EventHeaderType::INT64); + if (m_eventHeaderType != EventHeaderType::INT64) + { + AWS_LOGSTREAM_ERROR(CLASS_TAG, "Expected event header type is INT64, but encountered " << GetNameForEventHeaderType(m_eventHeaderType)); + return static_cast<uint64_t>(0); + } + return m_eventHeaderStaticValue.int64Value; + } + + /** + * Get header value as ByteBuffer. + * Log error if derived class doesn't override this function. + */ + inline ByteBuffer GetEventHeaderValueAsBytebuf() const + { + assert(m_eventHeaderType == EventHeaderType::BYTE_BUF); + if (m_eventHeaderType != EventHeaderType::BYTE_BUF) + { + AWS_LOGSTREAM_ERROR(CLASS_TAG, "Expected event header type is BYTE_BUF, but encountered " << GetNameForEventHeaderType(m_eventHeaderType)); + return ByteBuffer(); + } + return m_eventHeaderVariableLengthValue; + } + + /** + * Get header value as String. + * Log error if derived class doesn't override this function. + */ + inline Aws::String GetEventHeaderValueAsString() const + { + assert(m_eventHeaderType == EventHeaderType::STRING); + if (m_eventHeaderType != EventHeaderType::STRING) + { + AWS_LOGSTREAM_ERROR(CLASS_TAG, "Expected event header type is STRING, but encountered " << GetNameForEventHeaderType(m_eventHeaderType)); + return {}; + } + return Aws::String(reinterpret_cast<char*>(m_eventHeaderVariableLengthValue.GetUnderlyingData()), m_eventHeaderVariableLengthValue.GetLength()); + } + + /** + * Get header value as timestamp in 64 bit integer. + * Log error if derived class doesn't override this function. + */ + inline int64_t GetEventHeaderValueAsTimestamp() const + { + assert(m_eventHeaderType == EventHeaderType::TIMESTAMP); + if (m_eventHeaderType != EventHeaderType::TIMESTAMP) + { + AWS_LOGSTREAM_ERROR(CLASS_TAG, "Expected event header type is TIMESTAMP, but encountered " << GetNameForEventHeaderType(m_eventHeaderType)); + return static_cast<int64_t>(0); + } + return m_eventHeaderStaticValue.timestampValue; + } + + /** + * Get header value as UUID. + * Log error if derived class doesn't override this function. + */ + inline Aws::Utils::UUID GetEventHeaderValueAsUuid() const + { + assert(m_eventHeaderType == EventHeaderType::UUID); + assert(m_eventHeaderVariableLengthValue.GetLength() == 16u); + if (m_eventHeaderType != EventHeaderType::UUID) + { + AWS_LOGSTREAM_ERROR(CLASS_TAG, "Expected event header type is UUID, but encountered " << GetNameForEventHeaderType(m_eventHeaderType)); + char uuid[32] = {0}; + return Aws::Utils::UUID(uuid); + } + return Aws::Utils::UUID(m_eventHeaderVariableLengthValue.GetUnderlyingData()); + } + + inline const ByteBuffer& GetUnderlyingBuffer() const + { + return m_eventHeaderVariableLengthValue; + } + + private: + EventHeaderType m_eventHeaderType; + ByteBuffer m_eventHeaderVariableLengthValue; + union + { + bool boolValue; + uint8_t byteValue; + int16_t int16Value; + int32_t int32Value; + int64_t int64Value; + int64_t timestampValue; + } m_eventHeaderStaticValue; + }; + + typedef std::pair<Aws::String, EventHeaderValue> EventHeaderValuePair; + typedef Aws::Map<Aws::String, EventHeaderValue> EventHeaderValueCollection; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventMessage.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventMessage.h new file mode 100644 index 0000000000..4540fbe79c --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventMessage.h @@ -0,0 +1,122 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/event/EventHeader.h> + +namespace Aws +{ + namespace Utils + { + namespace Event + { + extern AWS_CORE_API const char EVENT_TYPE_HEADER[]; + extern AWS_CORE_API const char CONTENT_TYPE_HEADER[]; + extern AWS_CORE_API const char MESSAGE_TYPE_HEADER[]; + extern AWS_CORE_API const char ERROR_CODE_HEADER[]; + extern AWS_CORE_API const char ERROR_MESSAGE_HEADER[]; + extern AWS_CORE_API const char EXCEPTION_TYPE_HEADER[]; + + /** + * A typical message in event stream consists of two parts: Prelude and Data, as well as the prelude CRC and message CRC. + * Prelude consists of total byte length and headers byte length. + * Data consists of headers and payload. + */ + class AWS_CORE_API Message + { + public: + enum class MessageType + { + UNKNOWN, + EVENT, + REQUEST_LEVEL_ERROR, + REQUEST_LEVEL_EXCEPTION + }; + + enum class ContentType + { + UNKNOWN, + APPLICATION_OCTET_STREAM, + APPLICATION_JSON, + TEXT_PLAIN + }; + + static MessageType GetMessageTypeForName(const Aws::String& name); + static Aws::String GetNameForMessageType(MessageType value); + + static ContentType GetContentTypeForName(const Aws::String& name); + static Aws::String GetNameForContentType(ContentType value); + + + /** + * Clean up the message, including the metadata, headers and payload received. + */ + void Reset(); + + /** + * Get/set the total length of this message: prelude(8 bytes) + prelude CRC(4 bytes) + Data(headers length + payload length) + message CRC(4 bytes). + */ + inline void SetTotalLength(size_t length) + { + m_totalLength = length; + m_eventPayload.reserve(length); + } + + inline size_t GetTotalLength() const { return m_totalLength; } + + /** + * Get/set the length of the headers. + * Each header consists of: header name byte-length(1 byte) + header name + header value type(1 byte) + header value. + */ + inline void SetHeadersLength(size_t length) { m_headersLength = length; } + inline size_t GetHeadersLength() const { return m_headersLength; } + + /** + * Get/set the length of payload. + */ + inline void SetPayloadLength(size_t length) { m_payloadLength = length; } + inline size_t GetPayloadLength() const { return m_payloadLength; } + + /** + * Set/get event headers. + */ + inline void InsertEventHeader(const Aws::String& headerName, const EventHeaderValue& eventHeaderValue) + { + m_eventHeaders.emplace(Aws::Utils::Event::EventHeaderValuePair(headerName, eventHeaderValue)); + } + + inline const Aws::Utils::Event::EventHeaderValueCollection& GetEventHeaders() const { return m_eventHeaders; } + + /** + * Set event payload. + */ + void WriteEventPayload(const unsigned char* data, size_t length); + void WriteEventPayload(const Aws::Vector<unsigned char>& bits); + void WriteEventPayload(const Aws::String& bits); + /** + * Get the byte array of the payload with transferring ownership. + */ + Aws::Vector<unsigned char>&& GetEventPayloadWithOwnership() { return std::move(m_eventPayload); } + const Aws::Vector<unsigned char>& GetEventPayload() const { return m_eventPayload; } + Aws::Vector<unsigned char>& GetEventPayload() { return m_eventPayload; } + /** + * Convert byte array of the payload to string without transferring ownership. + */ + inline Aws::String GetEventPayloadAsString() { return Aws::String(m_eventPayload.begin(), m_eventPayload.end()); } + + private: + size_t m_totalLength; + size_t m_headersLength; + size_t m_payloadLength; + + Aws::Utils::Event::EventHeaderValueCollection m_eventHeaders; + Aws::Vector<unsigned char> m_eventPayload; + }; + + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStream.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStream.h new file mode 100644 index 0000000000..daa9cbf57d --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStream.h @@ -0,0 +1,8 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include <aws/core/utils/event/EventDecoderStream.h> +#include <aws/core/utils/event/EventEncoderStream.h> diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStreamBuf.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStreamBuf.h new file mode 100644 index 0000000000..ad5c440323 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStreamBuf.h @@ -0,0 +1,52 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <ios> +#include <aws/core/utils/event/EventStreamDecoder.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> + +namespace Aws +{ + namespace Utils + { + namespace Event + { + extern AWS_CORE_API const size_t DEFAULT_BUF_SIZE; + + /** + * Derived from std::streambuf, used as the underlying buffer for EventStream. + * Handle the payload from server side and pass data to underlying decoder. + */ + class AWS_CORE_API EventStreamBuf : public std::streambuf + { + public: + /** + * @param decoder decodes the stream from server side, so as to invoke related callback functions. + * @param bufferSize The length of buffer, will be 1024 bytes by default. + */ + EventStreamBuf(EventStreamDecoder& decoder, size_t bufferLength = DEFAULT_BUF_SIZE); + virtual ~EventStreamBuf(); + + protected: + std::streampos seekoff(std::streamoff off, std::ios_base::seekdir dir, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override; + std::streampos seekpos(std::streampos pos, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override; + + int underflow() override; + int overflow(int ch) override; + int sync() override; + + private: + void writeToDecoder(); + + ByteBuffer m_byteBuffer; + size_t m_bufferLength; + Aws::StringStream m_err; + EventStreamDecoder& m_decoder; + }; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStreamDecoder.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStreamDecoder.h new file mode 100644 index 0000000000..8f737e7bc7 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStreamDecoder.h @@ -0,0 +1,109 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/Array.h> +#include <aws/core/utils/event/EventStreamHandler.h> +#include <aws/event-stream/event_stream.h> + +namespace Aws +{ + namespace Utils + { + namespace Event + { + class AWS_CORE_API EventStreamDecoder + { + public: + EventStreamDecoder(EventStreamHandler* handler); + ~EventStreamDecoder(); + + /** + * Whether or not the decoder is in good state. Return false if the decoder encounters errors. + */ + inline explicit operator bool() const { return *m_eventStreamHandler; } + + /** + * A wrapper of aws_event_stream_streaming_decoder_pump in aws-c-event-stream. + * Pass data to the underlying decoder. + */ + void Pump(const ByteBuffer& data); + void Pump(const ByteBuffer& data, size_t length); + + /** + * Reset decoder and it's handler. + */ + void Reset(); + + /** + * Reset event stream handler of the decoder + */ + void ResetEventStreamHandler(EventStreamHandler* handler); + + protected: + /** + * Callback function invoked when payload data has been received. + * @param decoder The underlying decoder defined in the aws-c-event-stream. + * @param payload The payload data received, it doesn't belong to you, make a copy if necessary. + * @param isFinalSegment A flag indicates the current data is the last payload buffer for that message if it equals to 1. + * @param context A context pointer, will cast it to a pointer of flow handler. + */ + static void onPayloadSegment( + aws_event_stream_streaming_decoder* decoder, + aws_byte_buf* payload, + int8_t isFinalSegment, + void* context); + + /** + * Callback function invoked when a new message has arrived. + * @param decoder The underlying decoder defined in the aws-c-event-stream. + * @param prelude The metadata of the message, including total message length and header length. + * @param context A context pointer, will cast it to a pointer of flow handler. + */ + static void onPreludeReceived( + aws_event_stream_streaming_decoder* decoder, + aws_event_stream_message_prelude* prelude, + void* context); + + /** + * Callback function invoked when a header is encountered. + * @param decoder The underlying decoder defined in the aws-c-event-stream. + * @param prelude The metadata of the message, including total message length and header length. + * @param header A header of the message. + * @param context A context pointer, will cast it to a pointer of flow handler. + */ + static void onHeaderReceived( + aws_event_stream_streaming_decoder* decoder, + aws_event_stream_message_prelude* prelude, + aws_event_stream_header_value_pair* header, + void* context); + + /** + * Callback function invoked when an error is encountered. + * @param decoder The underlying decoder defined in aws-c-event-stream. + * @param prelude The metadata of the message, including total message length and header length. + * @param errorCode Error code indicates the type of the error encountered. + * @param message Error message indicates the details of the error encountered. + * @param context A context pointer, will cast it to a pointer of flow handler. + */ + static void onError( + aws_event_stream_streaming_decoder* decoder, + aws_event_stream_message_prelude* prelude, + int errorCode, + const char* message, + void* context); + + /** + * The underlying decoder defined in aws-c-event-stream. + * The decoder will invoke callback functions when the streaming messages received. + */ + aws_event_stream_streaming_decoder m_decoder; + EventStreamHandler* m_eventStreamHandler; + }; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStreamEncoder.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStreamEncoder.h new file mode 100644 index 0000000000..3cd06a9df2 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStreamEncoder.h @@ -0,0 +1,51 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSVector.h> +#include <aws/event-stream/event_stream.h> + +namespace Aws +{ + namespace Client + { + class AWSAuthSigner; + } + + namespace Utils + { + namespace Event + { + /** + * Utility class that wraps the logic of translating event messages to their binary format according to the + * AWS streaming specification. + * This class is _not_ thread-safe. + */ + class AWS_CORE_API EventStreamEncoder + { + public: + EventStreamEncoder(Aws::Client::AWSAuthSigner* signer = nullptr); + + + void SetSignatureSeed(const Aws::String& seed) { m_signatureSeed = seed; } + + void SetSigner(Aws::Client::AWSAuthSigner* signer) { m_signer = signer; } + + /** + * Encodes the input message in the event-stream binary format and signs the resulting bits. + * The signing is done via the signer member. + */ + Aws::Vector<unsigned char> EncodeAndSign(const Aws::Utils::Event::Message& msg); + private: + aws_event_stream_message Encode(const Aws::Utils::Event::Message& msg); + aws_event_stream_message Sign(aws_event_stream_message* msg); + Aws::Client::AWSAuthSigner* m_signer; + Aws::String m_signatureSeed; + }; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStreamErrors.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStreamErrors.h new file mode 100644 index 0000000000..d85e4fdd1f --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStreamErrors.h @@ -0,0 +1,47 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include <aws/core/client/CoreErrors.h> +#include <aws/core/Core_EXPORTS.h> + +namespace Aws +{ + namespace Utils + { + namespace Event + { + /** + * Errors encountered in event stream. + * These errors are associated with those in aws-c-event-stream library. + */ + enum class EventStreamErrors + { + EVENT_STREAM_NO_ERROR = 0, + EVENT_STREAM_BUFFER_LENGTH_MISMATCH = 0x1000, + EVENT_STREAM_INSUFFICIENT_BUFFER_LEN, + EVENT_STREAM_MESSAGE_FIELD_SIZE_EXCEEDED, + EVENT_STREAM_PRELUDE_CHECKSUM_FAILURE, + EVENT_STREAM_MESSAGE_CHECKSUM_FAILURE, + EVENT_STREAM_MESSAGE_INVALID_HEADERS_LEN, + EVENT_STREAM_MESSAGE_UNKNOWN_HEADER_TYPE, + EVENT_STREAM_MESSAGE_PARSER_ILLEGAL_STATE, + EVENT_STREAM_UNKNOWN_ERROR + }; + + namespace EventStreamErrorsMapper + { + /** + * Get name by its error type in event stream. + */ + AWS_CORE_API const char* GetNameForError(Event::EventStreamErrors error); + /** + * Get AWSError by EventStreamError. The Error type will always be CoreErrors::UNKNOWN as an internal error in Event Stream, and it's always not retryable. + */ + AWS_CORE_API Aws::Client::AWSError<Aws::Client::CoreErrors> GetAwsErrorForEventStreamError(Event::EventStreamErrors error); + } // namespace EventStreamErrorsMapper + } // namespace Event + } // namespace Utils +} // namespace Aws
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStreamHandler.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStreamHandler.h new file mode 100644 index 0000000000..257bfd8288 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/event/EventStreamHandler.h @@ -0,0 +1,147 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/http/HttpTypes.h> +#include <aws/core/utils/event/EventHeader.h> +#include <aws/core/utils/event/EventMessage.h> +#include <aws/core/utils/event/EventStreamErrors.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> +#include <cassert> + +namespace Aws +{ + namespace Utils + { + namespace Event + { + /** + * Handler of event stream. + * Includes context and callback function while scanning the event stream. + */ + class AWS_CORE_API EventStreamHandler + { + public: + EventStreamHandler() : + m_failure(false), m_internalError(EventStreamErrors::EVENT_STREAM_NO_ERROR), m_headersBytesReceived(0), m_payloadBytesReceived(0) + {} + + virtual ~EventStreamHandler() = default; + + /** + * Whether or not flow handler is in a good state. Return false if handler encounters errors. + */ + inline operator bool() const { return !m_failure; } + + /** + * Fail the handler from outside. + */ + inline void SetFailure() { m_failure = true; } + + /** + * Clean up current bytes of data received, as well as the latest message. + */ + inline virtual void Reset() + { + m_failure = false; + m_internalError = EventStreamErrors::EVENT_STREAM_NO_ERROR; + m_headersBytesReceived = 0; + m_payloadBytesReceived = 0; + + m_message.Reset(); + } + + /** + * Set internal Event Stream Errors, which is associated with errors in aws-c-event-stream library. + */ + inline void SetInternalError(int errorCode = 0) + { + m_internalError = static_cast<EventStreamErrors>(errorCode); + } + + /** + * Get internal Event Stream Errors. + */ + inline EventStreamErrors GetInternalError() + { + return m_internalError; + } + + /** + * The message is considered to completed with the following scenarios: + * 1. Message doesn't have headers or payloads. Or + * 2. Message has headers but doesn't have payloads. Or + * 3. Message has both headers and payloads. + */ + inline virtual bool IsMessageCompleted() + { + return m_message.GetHeadersLength() == m_headersBytesReceived && m_message.GetPayloadLength() == m_payloadBytesReceived; + } + + /** + * Set message metadata, including total message length, headers length and payload length. + */ + inline virtual void SetMessageMetadata(size_t totalLength, size_t headersLength, size_t payloadLength) + { + m_message.SetTotalLength(totalLength); + m_message.SetHeadersLength(headersLength); + m_message.SetPayloadLength(payloadLength); + assert(totalLength == 12/*prelude length*/ + headersLength + payloadLength + 4/*message crc length*/); + if (totalLength != headersLength + payloadLength + 16) + { + AWS_LOG_WARN("EventStreamHandler", "Message total length mismatch."); + } + } + + /** + * Write data to underlying stream, and update payload bytes received. + */ + inline virtual void WriteMessageEventPayload(const unsigned char* data, size_t dataLength) + { + m_message.WriteEventPayload(data, dataLength); + m_payloadBytesReceived += dataLength; + } + + /** + * Get underlying byte array of the message just received. + */ + inline virtual Aws::Vector<unsigned char>&& GetEventPayloadWithOwnership() { return m_message.GetEventPayloadWithOwnership(); } + + /** + * Convert underlying byte array to string without transferring ownership. + */ + inline virtual Aws::String GetEventPayloadAsString() { return m_message.GetEventPayloadAsString(); } + + /** + * Insert event header to a underlying event header value map, and update headers bytes received. + */ + inline virtual void InsertMessageEventHeader(const String& eventHeaderName, size_t eventHeaderLength, const Aws::Utils::Event::EventHeaderValue& eventHeaderValue) + { + m_message.InsertEventHeader(eventHeaderName, eventHeaderValue); + m_headersBytesReceived += eventHeaderLength; + } + + inline virtual const Aws::Utils::Event::EventHeaderValueCollection& GetEventHeaders() { return m_message.GetEventHeaders(); } + + /** + * Entry point of all callback functions. + * Will trigger associated functions based on m_message. + */ + virtual void OnEvent() = 0; + + private: + bool m_failure; + EventStreamErrors m_internalError; + size_t m_headersBytesReceived; + size_t m_payloadBytesReceived; + Aws::Utils::Event::Message m_message; + }; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/json/JsonSerializer.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/json/JsonSerializer.h new file mode 100644 index 0000000000..657ee6eff4 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/json/JsonSerializer.h @@ -0,0 +1,381 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/Array.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/memory/stl/AWSMap.h> +#include <aws/core/external/cjson/cJSON.h> + +#include <utility> + +namespace Aws +{ + namespace Utils + { + namespace Json + { + class JsonView; + /** + * JSON DOM manipulation class. + * To read or serialize use @ref View function. + */ + class AWS_CORE_API JsonValue + { + public: + /** + * Constructs empty JSON DOM. + */ + JsonValue(); + + /** + * Constructs a JSON DOM by parsing the input string. + */ + JsonValue(const Aws::String& value); + + /** + * Constructs a JSON DOM by parsing the text in the input stream. + */ + JsonValue(Aws::IStream& istream); + + /** + * Performs a deep copy of the JSON DOM parameter. + * Prefer using a @ref JsonView if copying is not needed. + */ + JsonValue(const JsonValue& value); + + /** + * Moves the ownership of the internal JSON DOM. + * No copying is performed. + */ + JsonValue(JsonValue&& value); + + ~JsonValue(); + + /** + * Performs a deep copy of the JSON DOM parameter. + */ + JsonValue& operator=(const JsonValue& other); + + /** + * Moves the ownership of the internal JSON DOM of the parameter to the current object. + * No copying is performed. + * A DOM currently owned by the object will be freed prior to copying. + * @warning This will result in invalidating any outstanding views of the current DOM. However, views + * to the moved-from DOM would still valid. + */ + JsonValue& operator=(JsonValue&& other); + + bool operator==(const JsonValue& other) const; + bool operator!=(const JsonValue& other) const; + + /** + * Adds a string to the top level of this node with key. + */ + JsonValue& WithString(const Aws::String& key, const Aws::String& value); + JsonValue& WithString(const char* key, const Aws::String& value); + + /** + * Converts the current JSON node to a string. + */ + JsonValue& AsString(const Aws::String& value); + + /** + * Adds a bool value with key to the top level of this node. + */ + JsonValue& WithBool(const Aws::String& key, bool value); + JsonValue& WithBool(const char* key, bool value); + + /** + * Converts the current JSON node to a bool. + */ + JsonValue& AsBool(bool value); + + /** + * Adds an integer value at key at the top level of this node. + */ + JsonValue& WithInteger(const Aws::String& key, int value); + JsonValue& WithInteger(const char* key, int value); + + /** + * Converts the current JSON node to an integer. + */ + JsonValue& AsInteger(int value); + + /** + * Adds a 64-bit integer value at key to the top level of this node. + */ + JsonValue& WithInt64(const Aws::String& key, long long value); + JsonValue& WithInt64(const char* key, long long value); + + /** + * Converts the current JSON node to a 64-bit integer. + */ + JsonValue& AsInt64(long long value); + + /** + * Adds a double value at key at the top level of this node. + */ + JsonValue& WithDouble(const Aws::String& key, double value); + JsonValue& WithDouble(const char* key, double value); + + /** + * Converts the current JSON node to a double. + */ + JsonValue& AsDouble(double value); + + /** + * Adds an array of strings to the top level of this node at key. + */ + JsonValue& WithArray(const Aws::String& key, const Array<Aws::String>& array); + JsonValue& WithArray(const char* key, const Array<Aws::String>& array); + + /** + * Adds an array of arbitrary JSON objects to the top level of this node at key. + * The values in the array parameter will be deep-copied. + */ + JsonValue& WithArray(const Aws::String& key, const Array<JsonValue>& array); + + /** + * Adds an array of arbitrary JSON objects to the top level of this node at key. + * The values in the array parameter will be moved-from. + */ + JsonValue& WithArray(const Aws::String& key, Array<JsonValue>&& array); + + /** + * Converts the current JSON node to an array whose values are deep-copied from the array parameter. + */ + JsonValue& AsArray(const Array<JsonValue>& array); + + /** + * Converts the current JSON node to an array whose values are moved from the array parameter. + */ + JsonValue& AsArray(Array<JsonValue>&& array); + + /** + * Adds a JSON object to the top level of this node at key. + * The object parameter is deep-copied. + */ + JsonValue& WithObject(const Aws::String& key, const JsonValue& value); + JsonValue& WithObject(const char* key, const JsonValue& value); + + /** + * Adds a JSON object to the top level of this node at key. + */ + JsonValue& WithObject(const Aws::String& key, JsonValue&& value); + JsonValue& WithObject(const char* key, JsonValue&& value); + + /** + * Converts the current JSON node to a JSON object by deep-copying the parameter. + */ + JsonValue& AsObject(const JsonValue& value); + + /** + * Converts the current JSON node to a JSON object by moving from the parameter. + */ + JsonValue& AsObject(JsonValue&& value); + + /** + * Returns true if the last parse request was successful. If this returns false, + * you can call GetErrorMessage() to find the cause. + */ + inline bool WasParseSuccessful() const + { + return m_wasParseSuccessful; + } + + /** + * Returns the last error message from a failed parse attempt. Returns empty string if no error. + */ + inline const Aws::String& GetErrorMessage() const + { + return m_errorMessage; + } + + /** + * Creates a view from the current root JSON node. + */ + JsonView View() const; + + private: + void Destroy(); + JsonValue(cJSON* value); + cJSON* m_value; + bool m_wasParseSuccessful; + Aws::String m_errorMessage; + friend class JsonView; + }; + + /** + * Provides read-only view to an existing JsonValue. This allows lightweight copying without making deep + * copies of the JsonValue. + * Note: This class does not extend the lifetime of the given JsonValue. It's your responsibility to ensure + * the lifetime of the JsonValue is extended beyond the lifetime of its view. + */ + class AWS_CORE_API JsonView + { + public: + /* constructors */ + JsonView(); + JsonView(const JsonValue& v); + JsonView& operator=(const JsonValue& v); + + /** + * Gets a string from this node by its key. + */ + Aws::String GetString(const Aws::String& key) const; + + /** + * Returns the value of this node as a string. + * The behavior is undefined if the node is _not_ of type string. + */ + Aws::String AsString() const; + + /** + * Gets a boolean value from this node by its key. + */ + bool GetBool(const Aws::String& key) const; + + /** + * Returns the value of this node as a boolean. + */ + bool AsBool() const; + + /** + * Gets an integer value from this node by its key. + * The integer is of the same size as an int on the machine. + */ + int GetInteger(const Aws::String& key) const; + + /** + * Returns the value of this node as an int. + */ + int AsInteger() const; + + /** + * Gets a 64-bit integer value from this node by its key. + * The value is 64-bit regardless of the platform/machine. + */ + int64_t GetInt64(const Aws::String& key) const; + + /** + * Returns the value of this node as 64-bit integer. + */ + int64_t AsInt64() const; + + /** + * Gets a double precision floating-point value from this node by its key. + */ + double GetDouble(const Aws::String& key) const; + + /** + * Returns the value of this node as a double precision floating-point. + */ + double AsDouble() const; + + /** + * Gets an array of JsonView objects from this node by its key. + */ + Array<JsonView> GetArray(const Aws::String& key) const; + + /** + * Returns the value of this node as an array of JsonView objects. + */ + Array<JsonView> AsArray() const; + + /** + * Gets a JsonView object from this node by its key. + */ + JsonView GetObject(const Aws::String& key) const; + + /** + * Returns the value of this node as a JsonView object. + */ + JsonView AsObject() const; + + /** + * Reads all json objects at the top level of this node (does not traverse the tree any further) + * along with their keys. + */ + Aws::Map<Aws::String, JsonView> GetAllObjects() const; + + /** + * Tests whether a value exists at the current node level for the given key. + * Returns true if a value has been found and its value is not null, false otherwise. + */ + bool ValueExists(const Aws::String& key) const; + + /** + * Tests whether a key exists at the current node level. + */ + bool KeyExists(const Aws::String& key) const; + + /** + * Tests whether the current value is a JSON object. + */ + bool IsObject() const; + + /** + * Tests whether the current value is a boolean. + */ + bool IsBool() const; + + /** + * Tests whether the current value is a string. + */ + bool IsString() const; + + /** + * Tests whether the current value is an int or int64_t. + * Returns false if the value is floating-point. + */ + bool IsIntegerType() const; + + /** + * Tests whether the current value is a floating-point. + */ + bool IsFloatingPointType() const; + + /** + * Tests whether the current value is a JSON array. + */ + bool IsListType() const; + + /** + * Tests whether the current value is NULL. + */ + bool IsNull() const; + + /** + * Writes the current JSON view without whitespace characters starting at the current level to a string. + * @param treatAsObject if the current value is empty, writes out '{}' rather than an empty string. + */ + Aws::String WriteCompact(bool treatAsObject = true) const; + + /** + * Writes the current JSON view to a string in a human friendly format. + * @param treatAsObject if the current value is empty, writes out '{}' rather than an empty string. + */ + Aws::String WriteReadable(bool treatAsObject = true) const; + + /** + * Creates a deep copy of the JSON value rooted in the current JSON view. + */ + JsonValue Materialize() const; + + private: + JsonView(cJSON* val); + JsonView& operator=(cJSON* val); + cJSON* m_value; + }; + + } // namespace Json + } // namespace Utils +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/AWSLogging.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/AWSLogging.h new file mode 100644 index 0000000000..be572ad23b --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/AWSLogging.h @@ -0,0 +1,50 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <memory> + +namespace Aws +{ + namespace Utils + { + namespace Logging + { + class LogSystemInterface; + + // Standard interface + + /** + * Call this at the beginning of your program, prior to any AWS calls. + */ + AWS_CORE_API void InitializeAWSLogging(const std::shared_ptr<LogSystemInterface>& logSystem); + + /** + * Call this at the exit point of your program, after all calls have finished. + */ + AWS_CORE_API void ShutdownAWSLogging(void); + + /** + * Get currently configured log system instance. + */ + AWS_CORE_API LogSystemInterface* GetLogSystem(); + + // Testing interface + + /** + * Replaces the current logger with a new one, while pushing the old one onto a 1-deep stack; primarily for testing + */ + AWS_CORE_API void PushLogger(const std::shared_ptr<LogSystemInterface> &logSystem); + + /** + * Pops the logger off the logger stack and replaces the current logger with it. Disables logging if the top logger is actually a nullptr + */ + AWS_CORE_API void PopLogger(); + + } // namespace Logging + } // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/ConsoleLogSystem.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/ConsoleLogSystem.h new file mode 100644 index 0000000000..b7fb714ed6 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/ConsoleLogSystem.h @@ -0,0 +1,45 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/logging/FormattedLogSystem.h> + +namespace Aws +{ + namespace Utils + { + namespace Logging + { + /** + * Log system interface that logs to std::cout + */ + class AWS_CORE_API ConsoleLogSystem : public FormattedLogSystem + { + public: + + using Base = FormattedLogSystem; + + ConsoleLogSystem(LogLevel logLevel) : + Base(logLevel) + {} + + virtual ~ConsoleLogSystem() {} + + /** + * Flushes buffered messages to stdout. + */ + void Flush() override; + + protected: + + virtual void ProcessFormattedStatement(Aws::String&& statement) override; + }; + + } // namespace Logging + } // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/DefaultLogSystem.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/DefaultLogSystem.h new file mode 100644 index 0000000000..dbeed83cb1 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/DefaultLogSystem.h @@ -0,0 +1,90 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/logging/FormattedLogSystem.h> +#include <aws/core/utils/logging/LogLevel.h> +#include <aws/core/utils/memory/stl/AWSVector.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> + +#include <thread> +#include <memory> +#include <mutex> +#include <atomic> +#include <condition_variable> + +namespace Aws +{ + namespace Utils + { + namespace Logging + { + /** + * Default behavior logger. It has a background thread that reads a log queue and prints the messages + * out to file as quickly as possible. This implementation also rolls the file every hour. + */ + class AWS_CORE_API DefaultLogSystem : public FormattedLogSystem + { + public: + using Base = FormattedLogSystem; + + /** + * Initialize the logging system to write to the supplied logfile output. Creates logging thread on construction. + */ + DefaultLogSystem(LogLevel logLevel, const std::shared_ptr<Aws::OStream>& logFile); + /** + * Initialize the logging system to write to a computed file path filenamePrefix + "timestamp.log". Creates logging thread + * on construction. + */ + DefaultLogSystem(LogLevel logLevel, const Aws::String& filenamePrefix); + + virtual ~DefaultLogSystem(); + + /** + * Flushes buffered messages to the file system. + * This method is thread-safe. + */ + void Flush() override; + + /** + * Structure containing semaphores, queue etc... + */ + struct LogSynchronizationData + { + public: + LogSynchronizationData() : m_stopLogging(false) {} + + std::mutex m_logQueueMutex; + std::condition_variable m_queueSignal; + Aws::Vector<Aws::String> m_queuedLogMessages; + bool m_stopLogging; + + private: + LogSynchronizationData(const LogSynchronizationData& rhs) = delete; + LogSynchronizationData& operator =(const LogSynchronizationData& rhs) = delete; + }; + + protected: + /** + * Pushes log onto the queue and notifies the background thread. + */ + virtual void ProcessFormattedStatement(Aws::String&& statement) override; + + private: + DefaultLogSystem(const DefaultLogSystem& rhs) = delete; + DefaultLogSystem& operator =(const DefaultLogSystem& rhs) = delete; + + LogSynchronizationData m_syncData; + + std::thread m_loggingThread; + }; + + } // namespace Logging + } // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/FormattedLogSystem.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/FormattedLogSystem.h new file mode 100644 index 0000000000..6157c45528 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/FormattedLogSystem.h @@ -0,0 +1,66 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/logging/LogSystemInterface.h> +#include <aws/core/utils/logging/LogLevel.h> + +#include <atomic> + +namespace Aws +{ + namespace Utils + { + namespace Logging + { + /** + * Logger that formats log messages into [LEVEL] timestamp [threadid] message + */ + class AWS_CORE_API FormattedLogSystem : public LogSystemInterface + { + public: + using Base = LogSystemInterface; + + /** + * Initializes log system with logLevel + */ + FormattedLogSystem(LogLevel logLevel); + virtual ~FormattedLogSystem() = default; + + /** + * Gets the currently configured log level. + */ + virtual LogLevel GetLogLevel(void) const override { return m_logLevel; } + /** + * Set a new log level. This has the immediate effect of changing the log output to the new level. + */ + void SetLogLevel(LogLevel logLevel) { m_logLevel.store(logLevel); } + + /** + * Does a printf style output to ProcessFormattedStatement. Don't use this, it's unsafe. See LogStream + */ + virtual void Log(LogLevel logLevel, const char* tag, const char* formatStr, ...) override; + + /** + * Writes the stream to ProcessFormattedStatement. + */ + virtual void LogStream(LogLevel logLevel, const char* tag, const Aws::OStringStream &messageStream) override; + + protected: + /** + * This is the method that most logger implementations will want to override. + * At this point the message is formatted and is ready to go to the output stream + */ + virtual void ProcessFormattedStatement(Aws::String&& statement) = 0; + + private: + std::atomic<LogLevel> m_logLevel; + }; + + } // namespace Logging + } // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/LogLevel.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/LogLevel.h new file mode 100644 index 0000000000..ff1dd36c0e --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/LogLevel.h @@ -0,0 +1,37 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ + namespace Utils + { + namespace Logging + { + + /** + * LogLevel used to control verbosity of logging system. + */ + enum class LogLevel : int + { + Off = 0, + Fatal = 1, + Error = 2, + Warn = 3, + Info = 4, + Debug = 5, + Trace = 6 + }; + + AWS_CORE_API Aws::String GetLogLevelName(LogLevel logLevel); + + } // namespace Logging + } // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/LogMacros.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/LogMacros.h new file mode 100644 index 0000000000..b400340de4 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/LogMacros.h @@ -0,0 +1,194 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/logging/LogLevel.h> +#include <aws/core/utils/logging/AWSLogging.h> +#include <aws/core/utils/logging/LogSystemInterface.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> + +// While macros are usually grotty, using them here lets us have a simple function call interface for logging that +// +// (1) Can be compiled out completely, so you don't even have to pay the cost to check the log level (which will be a virtual function call and a std::atomic<> read) if you don't want any AWS logging +// (2) If you use logging and the log statement doesn't pass the conditional log filter level, not only do you not pay the cost of building the log string, you don't pay the cost for allocating or +// getting any of the values used in building the log string, as they're in a scope (if-statement) that never gets entered. + +#ifdef DISABLE_AWS_LOGGING + + #define AWS_LOG(level, tag, ...) + #define AWS_LOG_FATAL(tag, ...) + #define AWS_LOG_ERROR(tag, ...) + #define AWS_LOG_WARN(tag, ...) + #define AWS_LOG_INFO(tag, ...) + #define AWS_LOG_DEBUG(tag, ...) + #define AWS_LOG_TRACE(tag, ...) + #define AWS_LOG_FLUSH() + + #define AWS_LOGSTREAM(level, tag, streamExpression) + #define AWS_LOGSTREAM_FATAL(tag, streamExpression) + #define AWS_LOGSTREAM_ERROR(tag, streamExpression) + #define AWS_LOGSTREAM_WARN(tag, streamExpression) + #define AWS_LOGSTREAM_INFO(tag, streamExpression) + #define AWS_LOGSTREAM_DEBUG(tag, streamExpression) + #define AWS_LOGSTREAM_TRACE(tag, streamExpression) + #define AWS_LOGSTREAM_FLUSH() + +#else + + #define AWS_LOG_FLUSH() \ + { \ + Aws::Utils::Logging::LogSystemInterface* logSystem = Aws::Utils::Logging::GetLogSystem(); \ + if ( logSystem ) \ + { \ + logSystem->Flush(); \ + } \ + } + + #define AWS_LOG(level, tag, ...) \ + { \ + Aws::Utils::Logging::LogSystemInterface* logSystem = Aws::Utils::Logging::GetLogSystem(); \ + if ( logSystem && logSystem->GetLogLevel() >= level ) \ + { \ + logSystem->Log(level, tag, __VA_ARGS__); \ + } \ + } + + #define AWS_LOG_FATAL(tag, ...) \ + { \ + Aws::Utils::Logging::LogSystemInterface* logSystem = Aws::Utils::Logging::GetLogSystem(); \ + if ( logSystem && logSystem->GetLogLevel() >= Aws::Utils::Logging::LogLevel::Fatal ) \ + { \ + logSystem->Log(Aws::Utils::Logging::LogLevel::Fatal, tag, __VA_ARGS__); \ + } \ + } + + #define AWS_LOG_ERROR(tag, ...) \ + { \ + Aws::Utils::Logging::LogSystemInterface* logSystem = Aws::Utils::Logging::GetLogSystem(); \ + if ( logSystem && logSystem->GetLogLevel() >= Aws::Utils::Logging::LogLevel::Error ) \ + { \ + logSystem->Log(Aws::Utils::Logging::LogLevel::Error, tag, __VA_ARGS__); \ + } \ + } + + #define AWS_LOG_WARN(tag, ...) \ + { \ + Aws::Utils::Logging::LogSystemInterface* logSystem = Aws::Utils::Logging::GetLogSystem(); \ + if ( logSystem && logSystem->GetLogLevel() >= Aws::Utils::Logging::LogLevel::Warn ) \ + { \ + logSystem->Log(Aws::Utils::Logging::LogLevel::Warn, tag, __VA_ARGS__); \ + } \ + } + + #define AWS_LOG_INFO(tag, ...) \ + { \ + Aws::Utils::Logging::LogSystemInterface* logSystem = Aws::Utils::Logging::GetLogSystem(); \ + if ( logSystem && logSystem->GetLogLevel() >= Aws::Utils::Logging::LogLevel::Info ) \ + { \ + logSystem->Log(Aws::Utils::Logging::LogLevel::Info, tag, __VA_ARGS__); \ + } \ + } + + #define AWS_LOG_DEBUG(tag, ...) \ + { \ + Aws::Utils::Logging::LogSystemInterface* logSystem = Aws::Utils::Logging::GetLogSystem(); \ + if ( logSystem && logSystem->GetLogLevel() >= Aws::Utils::Logging::LogLevel::Debug ) \ + { \ + logSystem->Log(Aws::Utils::Logging::LogLevel::Debug, tag, __VA_ARGS__); \ + } \ + } + + #define AWS_LOG_TRACE(tag, ...) \ + { \ + Aws::Utils::Logging::LogSystemInterface* logSystem = Aws::Utils::Logging::GetLogSystem(); \ + if ( logSystem && logSystem->GetLogLevel() >= Aws::Utils::Logging::LogLevel::Trace ) \ + { \ + logSystem->Log(Aws::Utils::Logging::LogLevel::Trace, tag, __VA_ARGS__); \ + } \ + } + + #define AWS_LOGSTREAM(level, tag, streamExpression) \ + { \ + Aws::Utils::Logging::LogSystemInterface* logSystem = Aws::Utils::Logging::GetLogSystem(); \ + if ( logSystem && logSystem->GetLogLevel() >= level ) \ + { \ + Aws::OStringStream logStream; \ + logStream << streamExpression; \ + logSystem->LogStream( logLevel, tag, logStream ); \ + } \ + } + + #define AWS_LOGSTREAM_FATAL(tag, streamExpression) \ + { \ + Aws::Utils::Logging::LogSystemInterface* logSystem = Aws::Utils::Logging::GetLogSystem(); \ + if ( logSystem && logSystem->GetLogLevel() >= Aws::Utils::Logging::LogLevel::Fatal ) \ + { \ + Aws::OStringStream logStream; \ + logStream << streamExpression; \ + logSystem->LogStream( Aws::Utils::Logging::LogLevel::Fatal, tag, logStream ); \ + } \ + } + + #define AWS_LOGSTREAM_ERROR(tag, streamExpression) \ + { \ + Aws::Utils::Logging::LogSystemInterface* logSystem = Aws::Utils::Logging::GetLogSystem(); \ + if ( logSystem && logSystem->GetLogLevel() >= Aws::Utils::Logging::LogLevel::Error ) \ + { \ + Aws::OStringStream logStream; \ + logStream << streamExpression; \ + logSystem->LogStream( Aws::Utils::Logging::LogLevel::Error, tag, logStream ); \ + } \ + } + + #define AWS_LOGSTREAM_WARN(tag, streamExpression) \ + { \ + Aws::Utils::Logging::LogSystemInterface* logSystem = Aws::Utils::Logging::GetLogSystem(); \ + if ( logSystem && logSystem->GetLogLevel() >= Aws::Utils::Logging::LogLevel::Warn ) \ + { \ + Aws::OStringStream logStream; \ + logStream << streamExpression; \ + logSystem->LogStream( Aws::Utils::Logging::LogLevel::Warn, tag, logStream ); \ + } \ + } + + #define AWS_LOGSTREAM_INFO(tag, streamExpression) \ + { \ + Aws::Utils::Logging::LogSystemInterface* logSystem = Aws::Utils::Logging::GetLogSystem(); \ + if ( logSystem && logSystem->GetLogLevel() >= Aws::Utils::Logging::LogLevel::Info ) \ + { \ + Aws::OStringStream logStream; \ + logStream << streamExpression; \ + logSystem->LogStream( Aws::Utils::Logging::LogLevel::Info, tag, logStream ); \ + } \ + } + + #define AWS_LOGSTREAM_DEBUG(tag, streamExpression) \ + { \ + Aws::Utils::Logging::LogSystemInterface* logSystem = Aws::Utils::Logging::GetLogSystem(); \ + if ( logSystem && logSystem->GetLogLevel() >= Aws::Utils::Logging::LogLevel::Debug ) \ + { \ + Aws::OStringStream logStream; \ + logStream << streamExpression; \ + logSystem->LogStream( Aws::Utils::Logging::LogLevel::Debug, tag, logStream ); \ + } \ + } + + #define AWS_LOGSTREAM_TRACE(tag, streamExpression) \ + { \ + Aws::Utils::Logging::LogSystemInterface* logSystem = Aws::Utils::Logging::GetLogSystem(); \ + if ( logSystem && logSystem->GetLogLevel() >= Aws::Utils::Logging::LogLevel::Trace ) \ + { \ + Aws::OStringStream logStream; \ + logStream << streamExpression; \ + logSystem->LogStream( Aws::Utils::Logging::LogLevel::Trace, tag, logStream ); \ + } \ + } + + #define AWS_LOGSTREAM_FLUSH() AWS_LOG_FLUSH() + +#endif // DISABLE_AWS_LOGGING diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/LogSystemInterface.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/LogSystemInterface.h new file mode 100644 index 0000000000..642d1c3022 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/logging/LogSystemInterface.h @@ -0,0 +1,51 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> + +namespace Aws +{ + namespace Utils + { + namespace Logging + { + enum class LogLevel : int; + + /** + * Interface for logging implementations. If you want to write your own logger, you can start here, though you may have more + * luck going down one more level to FormattedLogSystem. It does a bit more of the work for you and still gives you the ability + * to override the IO portion. + */ + class AWS_CORE_API LogSystemInterface + { + public: + virtual ~LogSystemInterface() = default; + + /** + * Gets the currently configured log level for this logger. + */ + virtual LogLevel GetLogLevel(void) const = 0; + /** + * Does a printf style output to the output stream. Don't use this, it's unsafe. See LogStream + */ + virtual void Log(LogLevel logLevel, const char* tag, const char* formatStr, ...) = 0; + /** + * Writes the stream to the output stream. + */ + virtual void LogStream(LogLevel logLevel, const char* tag, const Aws::OStringStream &messageStream) = 0; + /** + * Writes any buffered messages to the underlying device if the logger supports buffering. + */ + virtual void Flush() = 0; + }; + + } // namespace Logging + } // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/AWSMemory.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/AWSMemory.h new file mode 100644 index 0000000000..5b1221917a --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/AWSMemory.h @@ -0,0 +1,291 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/UnreferencedParam.h> +#include <aws/core/utils/memory/MemorySystemInterface.h> + +#include <memory> +#include <cstdlib> +#include <algorithm> +#include <type_traits> + +struct aws_allocator; + +namespace Aws +{ + namespace Utils + { + namespace Memory + { + /** + *InitializeAWSMemory should be called at the very start of your program + */ + AWS_CORE_API void InitializeAWSMemorySystem(MemorySystemInterface& memorySystem); + + /** + * ShutdownAWSMemory should be called the very end of your program + */ + AWS_CORE_API void ShutdownAWSMemorySystem(void); + + /** + * Get the globally install memory system, if it has been installed. + */ + AWS_CORE_API MemorySystemInterface* GetMemorySystem(); + + } // namespace Memory + } // namespace Utils + + /** + * ::new, ::delete, ::malloc, ::free, std::make_shared, and std::make_unique should not be used in SDK code + * use these functions instead or Aws::MakeShared + */ + AWS_CORE_API void* Malloc(const char* allocationTag, size_t allocationSize); + + /** + * ::new, ::delete, ::malloc, ::free, std::make_shared, and std::make_unique should not be used in SDK code + * use these functions instead or Aws::MakeShared + */ + AWS_CORE_API void Free(void* memoryPtr); + + AWS_CORE_API aws_allocator* get_aws_allocator(); + + /** + * ::new, ::delete, ::malloc, ::free, std::make_shared, and std::make_unique should not be used in SDK code + * use these functions instead or Aws::MakeShared + */ + template<typename T, typename ...ArgTypes> + T* New(const char* allocationTag, ArgTypes&&... args) + { + void *rawMemory = Malloc(allocationTag, sizeof(T)); + // http://stackoverflow.com/questions/6783993/placement-new-and-delete + T *constructedMemory = new (rawMemory) T(std::forward<ArgTypes>(args)...); + return constructedMemory; + } +/* + * dynamic_cast of all sorts do not work on MSVC if RTTI is turned off. + * This means that deleting an object via a pointer to one of its polymorphic base types that do not point to the + * address of their concrete class will result in undefined behavior. + * Example: + * struct Foo : InterfaceA, InterfaceB {}; + * Aws::Delete(pointerToInterfaceB); + */ +#if defined(_MSC_VER) && !defined(_CPPRTTI) + template<typename T> + void Delete(T* pointerToT) + { + if (pointerToT == nullptr) + { + return; + } + pointerToT->~T(); + Free(pointerToT); + } +#else + /** + * ::new, ::delete, ::malloc, ::free, std::make_shared, and std::make_unique should not be used in SDK code + * use these functions instead or Aws::MakeShared + */ + template<typename T> + typename std::enable_if<!std::is_polymorphic<T>::value>::type Delete(T* pointerToT) + { + if (pointerToT == nullptr) + { + return; + } + //http://stackoverflow.com/questions/6783993/placement-new-and-delete + pointerToT->~T(); + Free(pointerToT); + } + + template<typename T> + typename std::enable_if<std::is_polymorphic<T>::value>::type Delete(T* pointerToT) + { + if (pointerToT == nullptr) + { + return; + } + // deal with deleting objects that implement multiple interfaces + // see casting to pointer to void in http://en.cppreference.com/w/cpp/language/dynamic_cast + // https://stackoverflow.com/questions/8123776/are-there-practical-uses-for-dynamic-casting-to-void-pointer + // NOTE: on some compilers, calling the destructor before doing the dynamic_cast affects how calculation of + // the address of the most derived class. + void* mostDerivedT = dynamic_cast<void*>(pointerToT); + pointerToT->~T(); + Free(mostDerivedT); + } +#endif // _CPPRTTI + + template<typename T> + bool ShouldConstructArrayMembers() + { + return std::is_class<T>::value; + } + + template<typename T> + bool ShouldDestroyArrayMembers() + { + return !std::is_trivially_destructible<T>::value; + } + + /** + * ::new, ::delete, ::malloc, ::free, std::make_shared, and std::make_unique should not be used in SDK code + * use these functions instead or Aws::MakeShared + */ + template<typename T> + T* NewArray(std::size_t amount, const char* allocationTag) + { + if (amount > 0) + { + bool constructMembers = ShouldConstructArrayMembers<T>(); + bool trackMemberCount = ShouldDestroyArrayMembers<T>(); + + // if we need to remember the # of items in the array (because we need to call their destructors) then allocate extra memory and keep the # of items in the extra slot + std::size_t allocationSize = amount * sizeof(T); +#if defined(_MSC_VER) && _MSC_VER < 1900 + std::size_t headerSize = (std::max)(sizeof(std::size_t), __alignof(T)); +#else + std::size_t headerSize = (std::max)(sizeof(std::size_t), alignof(T)); +#endif + + if (trackMemberCount) + { + allocationSize += headerSize; + } + + void* rawMemory = Malloc(allocationTag, allocationSize); + T* pointerToT = nullptr; + + if (trackMemberCount) + { + std::size_t* pointerToAmount = reinterpret_cast<std::size_t*>(rawMemory); + *pointerToAmount = amount; + pointerToT = reinterpret_cast<T*>(reinterpret_cast<char*>(pointerToAmount) + headerSize); + + } + else + { + pointerToT = reinterpret_cast<T*>(rawMemory); + } + + if (constructMembers) + { + for (std::size_t i = 0; i < amount; ++i) + { + new (pointerToT + i) T; + } + } + + return pointerToT; + } + + return nullptr; + } + + /** + * ::new, ::delete, ::malloc, ::free, std::make_shared, and std::make_unique should not be used in SDK code + * use these functions instead or Aws::MakeShared + */ + template<typename T> + void DeleteArray(T* pointerToTArray) + { + if (pointerToTArray == nullptr) + { + return; + } + + bool destroyMembers = ShouldDestroyArrayMembers<T>(); + void* rawMemory = nullptr; + + if (destroyMembers) + { +#if defined(_MSC_VER) && _MSC_VER < 1900 + std::size_t headerSize = (std::max)(sizeof(std::size_t), __alignof(T)); +#else + std::size_t headerSize = (std::max)(sizeof(std::size_t), alignof(T)); +#endif + + std::size_t *pointerToAmount = reinterpret_cast<std::size_t*>(reinterpret_cast<char*>(pointerToTArray) - headerSize); + std::size_t amount = *pointerToAmount; + + for (std::size_t i = amount; i > 0; --i) + { + (pointerToTArray + i - 1)->~T(); + } + rawMemory = reinterpret_cast<void *>(pointerToAmount); + } + else + { + rawMemory = reinterpret_cast<void *>(pointerToTArray); + } + + Free(rawMemory); + } + + /** + * modeled from std::default_delete + */ + template<typename T> + struct Deleter + { + Deleter() {} + + template<class U, class = typename std::enable_if<std::is_convertible<U *, T *>::value, void>::type> + Deleter(const Deleter<U>&) + { + } + + void operator()(T *pointerToT) const + { + static_assert(0 < sizeof(T), "can't delete an incomplete type"); + Aws::Delete(pointerToT); + } + }; + + template< typename T > using UniquePtr = std::unique_ptr< T, Deleter< T > >; + + /** + * ::new, ::delete, ::malloc, ::free, std::make_shared, and std::make_unique should not be used in SDK code + * use these functions instead or Aws::MakeShared + */ + template<typename T, typename ...ArgTypes> + UniquePtr<T> MakeUnique(const char* allocationTag, ArgTypes&&... args) + { + return UniquePtr<T>(Aws::New<T>(allocationTag, std::forward<ArgTypes>(args)...)); + } + + template<typename T> + struct ArrayDeleter + { + ArrayDeleter() {} + + template<class U, class = typename std::enable_if<std::is_convertible<U *, T *>::value, void>::type> + ArrayDeleter(const ArrayDeleter<U>&) + { + } + + void operator()(T *pointerToTArray) const + { + static_assert(0 < sizeof(T), "can't delete an incomplete type"); + Aws::DeleteArray(pointerToTArray); + } + }; + + template< typename T > using UniqueArrayPtr = std::unique_ptr< T, ArrayDeleter< T > >; + + /** + * ::new, ::delete, ::malloc, ::free, std::make_shared, and std::make_unique should not be used in SDK code + * use these functions instead or Aws::MakeShared + */ + template<typename T, typename ...ArgTypes> + UniqueArrayPtr<T> MakeUniqueArray(std::size_t amount, const char* allocationTag, ArgTypes&&... args) + { + return UniqueArrayPtr<T>(Aws::NewArray<T>(amount, allocationTag, std::forward<ArgTypes>(args)...)); + } + +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/MemorySystemInterface.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/MemorySystemInterface.h new file mode 100644 index 0000000000..0a8341ff86 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/MemorySystemInterface.h @@ -0,0 +1,50 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <cstdlib> + +namespace Aws +{ + namespace Utils + { + namespace Memory + { + /** + * Central interface for memory management customizations. To create a custom memory manager, implement this interface and then + * call InitializeAWSMemorySystem(). + */ + class AWS_CORE_API MemorySystemInterface + { + public: + virtual ~MemorySystemInterface() = default; + + /** + * This is for initializing your memory manager in a static context. This can be empty if you don't need to do that. + */ + virtual void Begin() = 0; + /** + * This is for cleaning up your memory manager in a static context. This can be empty if you don't need to do that. + */ + virtual void End() = 0; + + /** + * Allocate your memory inside this method. blocksize and alignment are exactly the same as the std::allocator interfaces. + * The allocationTag parameter is for memory tracking; you don't have to handle it. + */ + virtual void* AllocateMemory(std::size_t blockSize, std::size_t alignment, const char *allocationTag = nullptr) = 0; + + /** + * Free the memory pointed to by memoryPtr. + */ + virtual void FreeMemory(void* memoryPtr) = 0; + }; + + } // namespace Memory + } // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSAllocator.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSAllocator.h new file mode 100644 index 0000000000..932408b761 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSAllocator.h @@ -0,0 +1,100 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/SDKConfig.h> +#include <aws/core/utils/memory/AWSMemory.h> +#include <aws/core/utils/memory/MemorySystemInterface.h> + +#include <memory> +#include <cstdlib> + +namespace Aws +{ +#ifdef USE_AWS_MEMORY_MANAGEMENT + /** + * Std allocator interface that is used for all STL types in the event that Custom Memory Management is being used. + */ + template <typename T> + class Allocator : public std::allocator<T> + { + public: + + typedef std::allocator<T> Base; + + Allocator() throw() : + Base() + {} + + Allocator(const Allocator<T>& a) throw() : + Base(a) + {} + + template <class U> + Allocator(const Allocator<U>& a) throw() : + Base(a) + {} + + ~Allocator() throw() {} + + typedef std::size_t size_type; + + template<typename U> + struct rebind + { + typedef Allocator<U> other; + }; + + typename Base::pointer allocate(size_type n, const void *hint = nullptr) + { + AWS_UNREFERENCED_PARAM(hint); + + return reinterpret_cast<typename Base::pointer>(Malloc("AWSSTL", n * sizeof(T))); + } + + void deallocate(typename Base::pointer p, size_type n) + { + AWS_UNREFERENCED_PARAM(n); + + Free(p); + } + + }; + +#ifdef __ANDROID__ +#if _GLIBCXX_FULLY_DYNAMIC_STRING == 0 + template< typename T > + bool operator ==(const Allocator< T >& lhs, const Allocator< T >& rhs) + { + AWS_UNREFERENCED_PARAM(lhs); + AWS_UNREFERENCED_PARAM(rhs); + + return false; + } +#endif // _GLIBCXX_FULLY_DYNAMIC_STRING == 0 +#endif // __ANDROID__ + +#else + + template< typename T > using Allocator = std::allocator<T>; + +#endif // USE_AWS_MEMORY_MANAGEMENT + /** + * Creates a shared_ptr using AWS Allocator hooks. + * allocationTag is for memory tracking purposes. + */ + template<typename T, typename ...ArgTypes> + std::shared_ptr<T> MakeShared(const char* allocationTag, ArgTypes&&... args) + { + AWS_UNREFERENCED_PARAM(allocationTag); + + return std::allocate_shared<T, Aws::Allocator<T>>(Aws::Allocator<T>(), std::forward<ArgTypes>(args)...); + } + + +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSDeque.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSDeque.h new file mode 100644 index 0000000000..ed63b8e939 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSDeque.h @@ -0,0 +1,19 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSAllocator.h> + +#include <deque> + +namespace Aws +{ + +template< typename T > using Deque = std::deque< T, Aws::Allocator< T > >; + +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSList.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSList.h new file mode 100644 index 0000000000..49341325a8 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSList.h @@ -0,0 +1,19 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSAllocator.h> + +#include <list> + +namespace Aws +{ + +template< typename T > using List = std::list< T, Aws::Allocator< T > >; + +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSMap.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSMap.h new file mode 100644 index 0000000000..66dc98bb8f --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSMap.h @@ -0,0 +1,33 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSAllocator.h> + +#include <map> +#include <unordered_map> +#include <cstring> + +namespace Aws +{ + +template< typename K, typename V > using Map = std::map< K, V, std::less< K >, Aws::Allocator< std::pair< const K, V > > >; +template< typename K, typename V > using UnorderedMap = std::unordered_map< K, V, std::hash< K >, std::equal_to< K >, Aws::Allocator< std::pair< const K, V > > >; +template< typename K, typename V > using MultiMap = std::multimap< K, V, std::less< K >, Aws::Allocator< std::pair< const K, V > > >; + +struct CompareStrings +{ + bool operator()(const char* a, const char* b) const + { + return std::strcmp(a, b) < 0; + } +}; + +template<typename V> using CStringMap = std::map<const char*, V, CompareStrings, Aws::Allocator<std::pair<const char*, V> > >; + +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSQueue.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSQueue.h new file mode 100644 index 0000000000..d45b245ad0 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSQueue.h @@ -0,0 +1,21 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSAllocator.h> +#include <aws/core/utils/memory/stl/AWSDeque.h> + +#include <deque> +#include <queue> + +namespace Aws +{ + +template< typename T > using Queue = std::queue< T, Deque< T > >; + +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSSet.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSSet.h new file mode 100644 index 0000000000..6aee204f39 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSSet.h @@ -0,0 +1,19 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSAllocator.h> + +#include <set> + +namespace Aws +{ + +template< typename T > using Set = std::set< T, std::less< T >, Aws::Allocator< T > >; + +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSStack.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSStack.h new file mode 100644 index 0000000000..7a3f561244 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSStack.h @@ -0,0 +1,21 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSAllocator.h> +#include <aws/core/utils/memory/stl/AWSDeque.h> + +#include <deque> +#include <stack> + +namespace Aws +{ + +template< typename T > using Stack = std::stack< T, Deque< T > >; + +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSStreamFwd.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSStreamFwd.h new file mode 100644 index 0000000000..335346a31b --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSStreamFwd.h @@ -0,0 +1,28 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <iostream> +#include <functional> + +namespace Aws +{ + +// Serves no purpose other than to help my conversion process +typedef std::basic_ifstream< char, std::char_traits< char > > IFStream; +typedef std::basic_ofstream< char, std::char_traits< char > > OFStream; +typedef std::basic_fstream< char, std::char_traits< char > > FStream; +typedef std::basic_istream< char, std::char_traits< char > > IStream; +typedef std::basic_ostream< char, std::char_traits< char > > OStream; +typedef std::basic_iostream< char, std::char_traits< char > > IOStream; +typedef std::istreambuf_iterator< char, std::char_traits< char > > IStreamBufIterator; + +using IOStreamFactory = std::function< Aws::IOStream*(void) >; + + +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSString.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSString.h new file mode 100644 index 0000000000..3cd013e3f8 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSString.h @@ -0,0 +1,108 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSAllocator.h> + +#include <functional> +#include <string> + +namespace Aws +{ + +#if defined(_GLIBCXX_FULLY_DYNAMIC_STRING) && _GLIBCXX_FULLY_DYNAMIC_STRING == 0 && defined(__ANDROID__) + +/* +using std::string with shared libraries is broken on android when using gnustl +due to the platform-level decision to set _GLIBCXX_FULLY_DYNAMIC_STRING to 0 + +The problem: + +(1) _GLIBCXX_FULLY_DYNAMIC_STRING is set to 0 in Android's c++config.h for gnustl +(2) The optimization that this enables is completely broken if using shared libraries and there is no way to opt out of using it. + An optimization that uses a comparison to a static memory address is death for shared libraries. + +Supposing you have a shared library B that depends on another shared library A. There are a variety of innocuous scenarios where you end up crashing +in the std::basic_string destructor because it's attempting to free a static memory address (&std::string::_Rep_Base::_S_empty_rep_storage -- you'll need to temporarily +flip the struct to "public:" in order to take this address from your code). +If you take the address of this location, you will get two +different answers depending on whether you query it in library A or library B (oddly enough, if you look the symbol itself up, it only shows up as public weak in +libgnustl_shared.so). When the string destructor is run from the context of library B, the _Rep::_M_dispose function will end up attempting to free +an address that is static memory (from library A). + + +Lessons (with the empty string optimization forced on you): + (1) You can't move std::strings across shared libraries (as a part of another class, Outcome in our case) + (2) If you default initialize a std::string member variable, you can't have a mismatched constructor/destructor pair such that one is in a cpp file and the other + is missing/implicit or defined in the header file + +Solutions: + +Use libc++ rather than gnustl + +For those who must use gnustl, we have provided a working solution by cobbling together a set of hacks: + +We prevent the empty string optimization from ever being run on our strings by: + (1) Make Aws::Allocator always fail equality checks with itself; this check is part of the empty string optimization in several std::basic_string constructors + (2) All other cases are prevented by turning Aws::String into a subclass whose default constructor and move operations go to baseclass versions which will not + perform the empty string optimization + +Those changes prevent crashes, but lead to very poor performance when using a string stream; every character added will result in multiple copies of the entire +string (ie, quadratic). + +To fix the performance problems, we have put together a set of replacement classes, SimpleStreamBuf and SimpleStringStream, that +replace std::stringstream and std::stringbuf in SDK code. These replacements use raw buffers rather than strings in order to +avoid the performance issues. + +This solution is only enabled if using gnustl on Android. In all other situations, normal STL types are used. +*/ + +using AndroidBasicString = std::basic_string< char, std::char_traits< char >, Aws::Allocator< char > >; + +class String : public AndroidBasicString +{ + public: + using Base = AndroidBasicString; + + String() : Base("") {} // allocator comparison failure will cause empty string optimisation to be skipped + String(const String& rhs ) : Base(rhs) {} + String(String&& rhs) : Base(rhs) {} // DO NOT CALL std::move, let this go to the const ref constructor + String(const AndroidBasicString& rhs) : Base(rhs) {} + String(AndroidBasicString&& rhs) : Base(rhs) {} // DO NOT CALL std::move, let this go to the const ref constructor + String(const char* str) : Base(str) {} + String(const char* str_begin, const char* str_end) : Base(str_begin, str_end) {} + String(const AndroidBasicString& str, size_type pos, size_type count) : Base(str, pos, count) {} + String(const String& str, size_type pos, size_type count) : Base(str, pos, count) {} + String(const char* str, size_type count) : Base(str, count) {} + String(size_type count, char c) : Base(count, c) {} + String(std::initializer_list<char> __l) : Base(__l) {} + + template<class _InputIterator> + String(_InputIterator __beg, _InputIterator __end) : Base(__beg, __end) {} + + String& operator=(const String& rhs) { Base::operator=(rhs); return *this; } + String& operator=(String&& rhs) { Base::operator=(rhs); return *this; } // might be ok to use std::move (base class uses swap) but let's be safe + String& operator=(const AndroidBasicString& rhs) { Base::operator=(rhs); return *this; } + String& operator=(AndroidBasicString&& rhs) { Base::operator=(rhs); return *this; } // might be ok to use std::move (base class uses swap) but let's be safe + String& operator=(const char* str) { Base::operator=(str); return *this; } +}; + +#else + +using String = std::basic_string< char, std::char_traits< char >, Aws::Allocator< char > >; + +#ifdef _WIN32 +using WString = std::basic_string< wchar_t, std::char_traits< wchar_t >, Aws::Allocator< wchar_t > >; +#endif + +#endif // __ANDROID + +} // namespace Aws + + + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSStringStream.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSStringStream.h new file mode 100644 index 0000000000..a5e6f4ae48 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSStringStream.h @@ -0,0 +1,42 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#if defined(_GLIBCXX_FULLY_DYNAMIC_STRING) && _GLIBCXX_FULLY_DYNAMIC_STRING == 0 && defined(__ANDROID__) + +#include <aws/core/utils/memory/stl/SimpleStringStream.h> + +#else + +#include <aws/core/utils/memory/stl/AWSAllocator.h> + +#include <sstream> + +#endif + +namespace Aws +{ + +#if defined(_GLIBCXX_FULLY_DYNAMIC_STRING) && _GLIBCXX_FULLY_DYNAMIC_STRING == 0 && defined(__ANDROID__) + +// see the large comment block in AWSString.h for an explanation +typedef Aws::SimpleStringStream StringStream; +typedef Aws::SimpleIStringStream IStringStream; +typedef Aws::SimpleOStringStream OStringStream; +typedef Aws::Utils::Stream::SimpleStreamBuf StringBuf; + +#else + +typedef std::basic_stringstream< char, std::char_traits< char >, Aws::Allocator< char > > StringStream; +typedef std::basic_istringstream< char, std::char_traits< char >, Aws::Allocator< char > > IStringStream; +typedef std::basic_ostringstream< char, std::char_traits< char >, Aws::Allocator< char > > OStringStream; +typedef std::basic_stringbuf< char, std::char_traits< char >, Aws::Allocator< char > > StringBuf; + +#endif + +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSVector.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSVector.h new file mode 100644 index 0000000000..d9f67825c7 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSVector.h @@ -0,0 +1,19 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/memory/stl/AWSAllocator.h> + +#include <vector> + +namespace Aws +{ + +template< typename T > using Vector = std::vector< T, Aws::Allocator< T > >; + +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/SimpleStringStream.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/SimpleStringStream.h new file mode 100644 index 0000000000..45c4d0a448 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/memory/stl/SimpleStringStream.h @@ -0,0 +1,126 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/stream/SimpleStreamBuf.h> + +#include <iostream> + +namespace Aws +{ + +class AWS_CORE_API SimpleStringStream : public std::iostream +{ + public: + + using char_type = char; + using traits_type = std::char_traits<char>; + using allocator_type = Aws::Allocator<char>; + using int_type = int; + using pos_type = std::streampos; + using off_type = std::streamoff; + + using base = std::iostream; + + SimpleStringStream(); + SimpleStringStream(const Aws::String& value); + + virtual ~SimpleStringStream() {} + + // disabling copies of course + SimpleStringStream(const SimpleStringStream& rhs) = delete; + SimpleStringStream& operator=(const SimpleStringStream& rhs) = delete; + + // also disabling moves until there's a valid need + SimpleStringStream(SimpleStringStream&& rhs) = delete; + SimpleStringStream& operator=(SimpleStringStream&& rhs) = delete; + + Aws::Utils::Stream::SimpleStreamBuf* rdbuf() const { return const_cast<Aws::Utils::Stream::SimpleStreamBuf*>(&m_streamBuffer); } + + Aws::String str() const { return m_streamBuffer.str(); } + void str(const Aws::String& value); + + private: + + Aws::Utils::Stream::SimpleStreamBuf m_streamBuffer; +}; + +class AWS_CORE_API SimpleIStringStream : public std::istream +{ + public: + + using char_type = char; + using traits_type = std::char_traits<char>; + using allocator_type = Aws::Allocator<char>; + using int_type = int; + using pos_type = std::streampos; + using off_type = std::streamoff; + + using base = std::istream; + + SimpleIStringStream(); + SimpleIStringStream(const Aws::String& value); + + virtual ~SimpleIStringStream() {} + + // disabling copies of course + SimpleIStringStream(const SimpleIStringStream& rhs) = delete; + SimpleIStringStream& operator=(const SimpleIStringStream& rhs) = delete; + + // also disabling moves until there's a valid need + SimpleIStringStream(SimpleIStringStream&& rhs) = delete; + SimpleIStringStream& operator=(SimpleIStringStream&& rhs) = delete; + + Aws::Utils::Stream::SimpleStreamBuf* rdbuf() const { return const_cast<Aws::Utils::Stream::SimpleStreamBuf*>(&m_streamBuffer); } + + Aws::String str() const { return m_streamBuffer.str(); } + void str(const Aws::String& value); + + private: + + Aws::Utils::Stream::SimpleStreamBuf m_streamBuffer; +}; + +class AWS_CORE_API SimpleOStringStream : public std::ostream +{ + public: + + using char_type = char; + using traits_type = std::char_traits<char>; + using allocator_type = Aws::Allocator<char>; + using int_type = int; + using pos_type = std::streampos; + using off_type = std::streamoff; + + using base = std::ostream; + + SimpleOStringStream(); + SimpleOStringStream(const Aws::String& value); + + virtual ~SimpleOStringStream() {} + + // disabling copies of course + SimpleOStringStream(const SimpleOStringStream& rhs) = delete; + SimpleOStringStream& operator=(const SimpleOStringStream& rhs) = delete; + + // also disabling moves until there's a valid need + SimpleOStringStream(SimpleOStringStream&& rhs) = delete; + SimpleOStringStream& operator=(SimpleOStringStream&& rhs) = delete; + + Aws::Utils::Stream::SimpleStreamBuf* rdbuf() const { return const_cast<Aws::Utils::Stream::SimpleStreamBuf*>(&m_streamBuffer); } + + Aws::String str() const { return m_streamBuffer.str(); } + void str(const Aws::String& value); + + private: + + Aws::Utils::Stream::SimpleStreamBuf m_streamBuffer; +}; + +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/ratelimiter/DefaultRateLimiter.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/ratelimiter/DefaultRateLimiter.h new file mode 100644 index 0000000000..974dbefb02 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/ratelimiter/DefaultRateLimiter.h @@ -0,0 +1,205 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/ratelimiter/RateLimiterInterface.h> + +#include <algorithm> +#include <mutex> +#include <thread> +#include <functional> + +namespace Aws +{ + namespace Utils + { + namespace RateLimits + { + /** + * High precision rate limiter. If you need to limit your bandwidth by a budget, this is very likely the implementation you want. + */ + template<typename CLOCK = std::chrono::high_resolution_clock, typename DUR = std::chrono::seconds, bool RENORMALIZE_RATE_CHANGES = true> + class DefaultRateLimiter : public RateLimiterInterface + { + public: + using Base = RateLimiterInterface; + + using InternalTimePointType = std::chrono::time_point<CLOCK>; + using ElapsedTimeFunctionType = std::function< InternalTimePointType() >; + + /** + * Initializes state, starts counts, does some basic validation. + */ + DefaultRateLimiter(int64_t maxRate, ElapsedTimeFunctionType elapsedTimeFunction = CLOCK::now) : + m_elapsedTimeFunction(elapsedTimeFunction), + m_maxRate(0), + m_accumulatorLock(), + m_accumulator(0), + m_accumulatorFraction(0), + m_accumulatorUpdated(), + m_replenishNumerator(0), + m_replenishDenominator(0), + m_delayNumerator(0), + m_delayDenominator(0) + { + // verify we're not going to divide by zero due to goofy type parameterization + static_assert(DUR::period::num > 0, "Rate duration must have positive numerator"); + static_assert(DUR::period::den > 0, "Rate duration must have positive denominator"); + static_assert(CLOCK::duration::period::num > 0, "RateLimiter clock duration must have positive numerator"); + static_assert(CLOCK::duration::period::den > 0, "RateLimiter clock duration must have positive denominator"); + + DefaultRateLimiter::SetRate(maxRate, true); + } + + virtual ~DefaultRateLimiter() = default; + + /** + * Calculates time in milliseconds that should be delayed before letting anymore data through. + */ + virtual DelayType ApplyCost(int64_t cost) override + { + std::lock_guard<std::recursive_mutex> lock(m_accumulatorLock); + + auto now = m_elapsedTimeFunction(); + auto elapsedTime = (now - m_accumulatorUpdated).count(); + + // replenish the accumulator based on how much time has passed + auto temp = elapsedTime * m_replenishNumerator + m_accumulatorFraction; + m_accumulator += temp / m_replenishDenominator; + m_accumulatorFraction = temp % m_replenishDenominator; + + // the accumulator is capped based on the maximum rate + m_accumulator = (std::min)(m_accumulator, m_maxRate); + if (m_accumulator == m_maxRate) + { + m_accumulatorFraction = 0; + } + + // if the accumulator is still negative, then we'll have to wait + DelayType delay(0); + if (m_accumulator < 0) + { + delay = DelayType(-m_accumulator * m_delayDenominator / m_delayNumerator); + } + + // apply the cost to the accumulator after the delay has been calculated; the next call will end up paying for our cost + m_accumulator -= cost; + m_accumulatorUpdated = now; + + return delay; + } + + /** + * Same as ApplyCost() but then goes ahead and sleeps the current thread. + */ + virtual void ApplyAndPayForCost(int64_t cost) override + { + auto costInMilliseconds = ApplyCost(cost); + if(costInMilliseconds.count() > 0) + { + std::this_thread::sleep_for(costInMilliseconds); + } + } + + /** + * Update the bandwidth rate to allow. + */ + virtual void SetRate(int64_t rate, bool resetAccumulator = false) override + { + std::lock_guard<std::recursive_mutex> lock(m_accumulatorLock); + + // rate must always be positive + rate = (std::max)(static_cast<int64_t>(1), rate); + + if (resetAccumulator) + { + m_accumulator = rate; + m_accumulatorFraction = 0; + m_accumulatorUpdated = m_elapsedTimeFunction(); + } + else + { + // sync the accumulator to current time + ApplyCost(0); // this call is why we need a recursive mutex + + if (ShouldRenormalizeAccumulatorOnRateChange()) + { + // now renormalize the accumulator and its fractional part against the new rate + // the idea here is we want to preserve the desired wait based on the previous rate + // + // As an example: + // Say we had a rate of 100/s and our accumulator was -500 (ie the next ApplyCost would incur a 5 second delay) + // If we change the rate to 1000/s and want to preserve that delay, we need to scale the accumulator to -5000 + m_accumulator = m_accumulator * rate / m_maxRate; + m_accumulatorFraction = m_accumulatorFraction * rate / m_maxRate; + } + } + + m_maxRate = rate; + + // Helper constants that represent the amount replenished per CLOCK time period; use the gcd to reduce them in order to try and minimize the chance of integer overflow + m_replenishNumerator = m_maxRate * DUR::period::den * CLOCK::duration::period::num; + m_replenishDenominator = DUR::period::num * CLOCK::duration::period::den; + auto gcd = ComputeGCD(m_replenishNumerator, m_replenishDenominator); + m_replenishNumerator /= gcd; + m_replenishDenominator /= gcd; + + // Helper constants that represent the delay per unit of costAccumulator; use the gcd to reduce them in order to try and minimize the chance of integer overflow + m_delayNumerator = m_maxRate * DelayType::period::num * DUR::period::den; + m_delayDenominator = DelayType::period::den * DUR::period::num; + gcd = ComputeGCD(m_delayNumerator, m_delayDenominator); + m_delayNumerator /= gcd; + m_delayDenominator /= gcd; + } + + private: + + int64_t ComputeGCD(int64_t num1, int64_t num2) const + { + // Euclid's + while (num2 != 0) + { + int64_t rem = num1 % num2; + num1 = num2; + num2 = rem; + } + + return num1; + } + + bool ShouldRenormalizeAccumulatorOnRateChange() const { return RENORMALIZE_RATE_CHANGES; } + + /// Function that returns the current time + ElapsedTimeFunctionType m_elapsedTimeFunction; + + /// The rate we want to limit to + int64_t m_maxRate; + + /// We need to pretty much lock everything while either setting the rate or applying a cost + std::recursive_mutex m_accumulatorLock; + + /// Tracks how much "rate" we currently have to give; if this drops below zero then we start having to wait in order to perform operations and maintain the rate + /// Replenishes over time based on m_maxRate + int64_t m_accumulator; + + /// Updates can occur at any time, leading to a fractional accumulation; represents the fraction (m_accumulatorFraction / m_replenishDenominator) + int64_t m_accumulatorFraction; + + /// Last time point the accumulator was updated + InternalTimePointType m_accumulatorUpdated; + + /// Some helper constants that represents fixed (per m_maxRate) ratios used in the delay and replenishment calculations + int64_t m_replenishNumerator; + int64_t m_replenishDenominator; + int64_t m_delayNumerator; + int64_t m_delayDenominator; + }; + + } // namespace RateLimits + } // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/ratelimiter/RateLimiterInterface.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/ratelimiter/RateLimiterInterface.h new file mode 100644 index 0000000000..578c9ed844 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/ratelimiter/RateLimiterInterface.h @@ -0,0 +1,45 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <stdint.h> +#include <chrono> + +namespace Aws +{ + namespace Utils + { + namespace RateLimits + { + /** + * Interface for bandwidth limiters. You likely don't want to implement your own as DefaultRateLimiter is probably what you need. + * If you need to implement one, then this is the interface to implement. + */ + class RateLimiterInterface + { + public: + using DelayType = std::chrono::milliseconds; + + virtual ~RateLimiterInterface() {} + /** + * Calculates time in milliseconds that should be delayed before letting anymore data through. + */ + virtual DelayType ApplyCost(int64_t cost) = 0; + /** + * Same as ApplyCost() but then goes ahead and sleeps the current thread. + */ + virtual void ApplyAndPayForCost(int64_t cost) = 0; + /** + * Update the bandwidth rate to allow. + */ + virtual void SetRate(int64_t rate, bool resetAccumulator = false) = 0; + }; + + } // namespace RateLimits + } // namespace Utils +} // namespace Aws
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/stream/ConcurrentStreamBuf.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/stream/ConcurrentStreamBuf.h new file mode 100644 index 0000000000..9ef7d9763e --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/stream/ConcurrentStreamBuf.h @@ -0,0 +1,58 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/auth/AWSAuthSigner.h> +#include <aws/common/array_list.h> + +#include <mutex> +#include <condition_variable> +#include <streambuf> +#include <ios> +#include <cassert> + +namespace Aws +{ + namespace Utils + { + namespace Stream + { + /** + * A thread-safe streambuf implementation that allows simultaneous reading and writing. + * NOTE: iostreams maintain state for readers and writers. This means that you can have at most two + * concurrent threads, one for reading and one for writing. Multiple readers or multiple writers are not + * thread-safe and will result in race-conditions. + */ + class AWS_CORE_API ConcurrentStreamBuf : public std::streambuf + { + public: + + explicit ConcurrentStreamBuf(size_t bufferLength = 4 * 1024); + + void SetEof(); + + protected: + std::streampos seekoff(std::streamoff off, std::ios_base::seekdir dir, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override; + std::streampos seekpos(std::streampos pos, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override; + + int underflow() override; + int overflow(int ch) override; + int sync() override; + std::streamsize showmanyc() override; + + void FlushPutArea(); + + private: + Aws::Vector<unsigned char> m_getArea; + Aws::Vector<unsigned char> m_putArea; + Aws::Vector<unsigned char> m_backbuf; // used to shuttle data from the put area to the get area + std::mutex m_lock; // synchronize access to the common backbuffer + std::condition_variable m_signal; + bool m_eof; + }; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/stream/PreallocatedStreamBuf.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/stream/PreallocatedStreamBuf.h new file mode 100644 index 0000000000..ad9dc2a929 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/stream/PreallocatedStreamBuf.h @@ -0,0 +1,56 @@ + +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/Array.h> +#include <streambuf> + +namespace Aws +{ + namespace Utils + { + namespace Stream + { + /** + * this is a stream buf to use with std::iostream that uses a preallocated buffer under the hood. + */ + class AWS_CORE_API PreallocatedStreamBuf : public std::streambuf + { + public: + /** + * Initialize the stream buffer with a pointer to your buffer. This class never takes ownership + * of the buffer. It is your responsibility to delete it once the stream is no longer in use. + * @param buffer buffer to initialize from. + * @param lengthToRead length in bytes to actually use in the buffer (e.g. you have a 1kb buffer, but only want the stream + * to see 500 b of it. + */ + PreallocatedStreamBuf(unsigned char* buffer, uint64_t lengthToRead); + + PreallocatedStreamBuf(const PreallocatedStreamBuf&) = delete; + PreallocatedStreamBuf& operator=(const PreallocatedStreamBuf&) = delete; + + PreallocatedStreamBuf(PreallocatedStreamBuf&& toMove) = delete; + PreallocatedStreamBuf& operator=(PreallocatedStreamBuf&&) = delete; + + /** + * Get the buffer that is being used by the stream buffer. + * @return Pointer to the underlying buffer (probably for a Aws::Delete() call). + */ + unsigned char* GetBuffer() { return m_underlyingBuffer; } + + protected: + pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override; + pos_type seekpos(pos_type pos, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override; + + private: + unsigned char* m_underlyingBuffer; + const uint64_t m_lengthToRead; + }; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/stream/ResponseStream.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/stream/ResponseStream.h new file mode 100644 index 0000000000..e82e6448cd --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/stream/ResponseStream.h @@ -0,0 +1,74 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/AWSMemory.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> + +namespace Aws +{ + namespace Utils + { + namespace Stream + { + /** + * Encapsulates and manages ownership of custom response streams. This is a move only type. + */ + class AWS_CORE_API ResponseStream + { + public: + /** + * sets underlying stream to nullptr + */ + ResponseStream(); + /** + * moves the underlying stream + */ + ResponseStream(ResponseStream&&); + /** + * Uses factory to allocate underlying stream + */ + ResponseStream(const Aws::IOStreamFactory& factory); + /** + * Takes ownership of an underlying stream. + */ + ResponseStream(IOStream* underlyingStreamToManage); + ResponseStream(const ResponseStream&) = delete; + ~ResponseStream(); + + /** + * moves the underlying stream + */ + ResponseStream& operator=(ResponseStream&&); + ResponseStream& operator=(const ResponseStream&) = delete; + + /** + * Gives access to underlying stream, but keep in mind that this changes state of the stream + */ + inline Aws::IOStream& GetUnderlyingStream() const { return *m_underlyingStream; } + + private: + void ReleaseStream(); + + Aws::IOStream* m_underlyingStream; + }; + + class AWS_CORE_API DefaultUnderlyingStream : public Aws::IOStream + { + public: + using Base = Aws::IOStream; + + DefaultUnderlyingStream(); + DefaultUnderlyingStream(Aws::UniquePtr<std::streambuf> buf); + virtual ~DefaultUnderlyingStream(); + }; + + AWS_CORE_API Aws::IOStream* DefaultResponseStreamFactoryMethod(); + + } //namespace Stream + } //namespace Utils +} //namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/stream/SimpleStreamBuf.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/stream/SimpleStreamBuf.h new file mode 100644 index 0000000000..ef12c60ba3 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/stream/SimpleStreamBuf.h @@ -0,0 +1,64 @@ + +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/memory/stl/AWSVector.h> +#include <streambuf> + +namespace Aws +{ +namespace Utils +{ +namespace Stream +{ + /** + * A replacement for std::stringbuf when using Android and gnustl together + */ + class AWS_CORE_API SimpleStreamBuf : public std::streambuf + { + public: + + using base = std::streambuf; + + SimpleStreamBuf(); + explicit SimpleStreamBuf(const Aws::String& value); + + SimpleStreamBuf(const SimpleStreamBuf&) = delete; + SimpleStreamBuf& operator=(const SimpleStreamBuf&) = delete; + + SimpleStreamBuf(SimpleStreamBuf&& toMove) = delete; + SimpleStreamBuf& operator=(SimpleStreamBuf&&) = delete; + + virtual ~SimpleStreamBuf(); + + Aws::String str() const; + void str(const Aws::String& value); + + void swap(SimpleStreamBuf& rhs); + + protected: + virtual std::streampos seekoff(std::streamoff off, std::ios_base::seekdir dir, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override; + virtual std::streampos seekpos(std::streampos pos, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override; + + virtual int overflow (int c = EOF) override; + virtual int underflow() override; + + virtual std::streamsize xsputn(const char* s, std::streamsize n) override; + + private: + + bool GrowBuffer(); + + char* m_buffer; + size_t m_bufferSize; + }; + +} +} +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/threading/Executor.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/threading/Executor.h new file mode 100644 index 0000000000..36975af513 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/threading/Executor.h @@ -0,0 +1,119 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/memory/stl/AWSQueue.h> +#include <aws/core/utils/memory/stl/AWSVector.h> +#include <aws/core/utils/memory/stl/AWSMap.h> +#include <aws/core/utils/threading/Semaphore.h> +#include <functional> +#include <future> +#include <mutex> +#include <atomic> + +namespace Aws +{ + namespace Utils + { + namespace Threading + { + class ThreadTask; + + /** + * Interface for implementing an Executor, to implement a custom thread execution strategy, inherit from this class + * and override SubmitToThread(). + */ + class AWS_CORE_API Executor + { + public: + virtual ~Executor() = default; + + /** + * Send function and its arguments to the SubmitToThread function. + */ + template<class Fn, class ... Args> + bool Submit(Fn&& fn, Args&& ... args) + { + std::function<void()> callable{ std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...) }; + return SubmitToThread(std::move(callable)); + } + + protected: + /** + * To implement your own executor implementation, then simply subclass Executor and implement this method. + */ + virtual bool SubmitToThread(std::function<void()>&&) = 0; + }; + + + /** + * Default Executor implementation. Simply spawns a thread and detaches it. + */ + class AWS_CORE_API DefaultExecutor : public Executor + { + public: + DefaultExecutor() : m_state(State::Free) {} + ~DefaultExecutor(); + protected: + enum class State + { + Free, Locked, Shutdown + }; + bool SubmitToThread(std::function<void()>&&) override; + void Detach(std::thread::id id); + std::atomic<State> m_state; + Aws::UnorderedMap<std::thread::id, std::thread> m_threads; + }; + + enum class OverflowPolicy + { + QUEUE_TASKS_EVENLY_ACCROSS_THREADS, + REJECT_IMMEDIATELY + }; + + /** + * Thread Pool Executor implementation. + */ + class AWS_CORE_API PooledThreadExecutor : public Executor + { + public: + PooledThreadExecutor(size_t poolSize, OverflowPolicy overflowPolicy = OverflowPolicy::QUEUE_TASKS_EVENLY_ACCROSS_THREADS); + ~PooledThreadExecutor(); + + /** + * Rule of 5 stuff. + * Don't copy or move + */ + PooledThreadExecutor(const PooledThreadExecutor&) = delete; + PooledThreadExecutor& operator =(const PooledThreadExecutor&) = delete; + PooledThreadExecutor(PooledThreadExecutor&&) = delete; + PooledThreadExecutor& operator =(PooledThreadExecutor&&) = delete; + + protected: + bool SubmitToThread(std::function<void()>&&) override; + + private: + Aws::Queue<std::function<void()>*> m_tasks; + std::mutex m_queueLock; + Aws::Utils::Threading::Semaphore m_sync; + Aws::Vector<ThreadTask*> m_threadTaskHandles; + size_t m_poolSize; + OverflowPolicy m_overflowPolicy; + + /** + * Once you call this, you are responsible for freeing the memory pointed to by task. + */ + std::function<void()>* PopTask(); + bool HasTasks(); + + friend class ThreadTask; + }; + + + } // namespace Threading + } // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/threading/ReaderWriterLock.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/threading/ReaderWriterLock.h new file mode 100644 index 0000000000..5d757dcecb --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/threading/ReaderWriterLock.h @@ -0,0 +1,116 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <aws/core/utils/threading/Semaphore.h> +#include <mutex> +#include <atomic> +#include <condition_variable> +#include <cstdint> + +namespace Aws +{ + namespace Utils + { + namespace Threading + { + /** + * This lock is optimized for frequent reads and infrequent writes. + * However, writers get priority to the lock. + */ + class AWS_CORE_API ReaderWriterLock + { + public: + ReaderWriterLock(); + /** + * Enters the lock in Reader-mode. + * This call blocks until no writers are acquiring the lock. + */ + void LockReader(); + + /** + * Decrements the readers count by one and if the count is zero, signals any waiting writers to acquire + * the lock. + * NOTE: Calling this function without a matching LockReader results in undefined behavior. + */ + void UnlockReader(); + + /** + * Enters the lock in Writer-mode. + * This call blocks until no readers nor writers are acquiring the lock. + */ + void LockWriter(); + + /** + * Decrements the number of writers by one and signals any waiting readers or writers to acquire the + * lock. + * NOTE: Calling this function without a matching LockWriter results in undefined behavior. + */ + void UnlockWriter(); + private: + std::atomic<int64_t> m_readers; + std::atomic<int64_t> m_holdouts; + Semaphore m_readerSem; + Semaphore m_writerSem; + std::mutex m_writerLock; + }; + + class AWS_CORE_API ReaderLockGuard + { + public: + explicit ReaderLockGuard(ReaderWriterLock& rwl) : m_rwlock(rwl), m_upgraded(false) + { + m_rwlock.LockReader(); + } + + void UpgradeToWriterLock() + { + m_rwlock.UnlockReader(); + m_rwlock.LockWriter(); + m_upgraded = true; + } + + ~ReaderLockGuard() + { + if(m_upgraded) + { + m_rwlock.UnlockWriter(); + } + else + { + m_rwlock.UnlockReader(); + } + } + // for VS2013 + ReaderLockGuard(const ReaderLockGuard&) = delete; + ReaderLockGuard& operator=(const ReaderLockGuard&) = delete; + private: + ReaderWriterLock& m_rwlock; + bool m_upgraded; + }; + + class AWS_CORE_API WriterLockGuard + { + public: + explicit WriterLockGuard(ReaderWriterLock& rwl) : m_rwlock(rwl) + { + m_rwlock.LockWriter(); + } + + ~WriterLockGuard() + { + m_rwlock.UnlockWriter(); + } + // for VS2013 + WriterLockGuard(const WriterLockGuard&) = delete; + WriterLockGuard& operator=(const WriterLockGuard&) = delete; + private: + ReaderWriterLock& m_rwlock; + }; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/threading/Semaphore.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/threading/Semaphore.h new file mode 100644 index 0000000000..bad50532dd --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/threading/Semaphore.h @@ -0,0 +1,45 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <mutex> +#include <condition_variable> + +namespace Aws +{ + namespace Utils + { + namespace Threading + { + class AWS_CORE_API Semaphore { + public: + /** + * Initializes a new instance of Semaphore class specifying the initial number of entries and + * the maximum number of concurrent entries. + */ + Semaphore(size_t initialCount, size_t maxCount); + /** + * Blocks the current thread until it receives a signal. + */ + void WaitOne(); + /** + * Exits the semaphore once. + */ + void Release(); + /** + * Exit the semaphore up to the maximum number of entries available. + */ + void ReleaseAll(); + private: + size_t m_count; + const size_t m_maxCount; + std::mutex m_mutex; + std::condition_variable m_syncPoint; + }; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/threading/ThreadTask.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/threading/ThreadTask.h new file mode 100644 index 0000000000..79326b3a15 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/threading/ThreadTask.h @@ -0,0 +1,48 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> +#include <functional> +#include <thread> +#include <atomic> + +namespace Aws +{ + namespace Utils + { + namespace Threading + { + class PooledThreadExecutor; + + class AWS_CORE_API ThreadTask + { + public: + ThreadTask(PooledThreadExecutor& executor); + ~ThreadTask(); + + /** + * Rule of 5 stuff. + * Don't copy or move + */ + ThreadTask(const ThreadTask&) = delete; + ThreadTask& operator =(const ThreadTask&) = delete; + ThreadTask(ThreadTask&&) = delete; + ThreadTask& operator =(ThreadTask&&) = delete; + + void StopProcessingWork(); + + protected: + void MainTaskRunner(); + + private: + std::atomic<bool> m_continue; + PooledThreadExecutor& m_executor; + std::thread m_thread; + }; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/xml/XmlSerializer.h b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/xml/XmlSerializer.h new file mode 100644 index 0000000000..d1ca79ffab --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include/aws/core/utils/xml/XmlSerializer.h @@ -0,0 +1,218 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#pragma once + +#include <aws/core/Core_EXPORTS.h> + +#include <aws/core/utils/Outcome.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/utils/memory/stl/AWSString.h> + +namespace Aws +{ + namespace External + { + namespace tinyxml2 + { + class XMLNode; + + class XMLDocument; + } // namespace tinyxml2 + } // namespace External +} // namespace Aws + +namespace Aws +{ + template<typename PAYLOAD_TYPE> + class AmazonWebServiceResult; + namespace Client + { + enum class CoreErrors; + template<typename ERROR_TYPE> + class AWSError; + class AWSXMLClient; + } // namespace Client + namespace Utils + { + namespace Xml + { + /** + * Converts escaped xml text back to the original characters (e.g. < ! > = etc...) + */ + AWS_CORE_API Aws::String DecodeEscapedXmlText(const Aws::String& textToDecode); + + class XmlDocument; + + /** + * Node in an Xml Document + */ + class AWS_CORE_API XmlNode + { + public: + /** + * copies node and document over. + */ + XmlNode(const XmlNode& other); + /** + * copies node and document over. + */ + XmlNode& operator=(const XmlNode& other); + /** + * Get the name of the node. + */ + const Aws::String GetName() const; + /** + * Set the name of the node. + */ + void SetName(const Aws::String& name); + /** + * Get Value of an attribute specified by name. + */ + const Aws::String GetAttributeValue(const Aws::String& name) const; + /** + * Set an attribute at name to value + */ + void SetAttributeValue(const Aws::String& name, const Aws::String& value); + /** + * Get the inner text of the node (potentially includes other nodes) + */ + Aws::String GetText() const; + /** + * Set the inner text of the node + */ + void SetText(const Aws::String& textValue); + /** + * returns true if this node has another sibling. + */ + bool HasNextNode() const; + /** + * returns the next sibling. + */ + XmlNode NextNode() const; + /** + * returns the next sibling that matches node name. + */ + XmlNode NextNode(const char* name) const; + /** + * returns the next sibling that matches node name. + */ + XmlNode NextNode(const Aws::String& name) const; + /** + * return the first child node of this node. + */ + XmlNode FirstChild() const; + /** + * returns the first child node of this node that has name. + */ + XmlNode FirstChild(const char* name) const; + /** + * returns the first child node of this node that has name. + */ + XmlNode FirstChild(const Aws::String& name) const; + /** + * returns true if this node has child nodes. + */ + bool HasChildren() const; + /** + * returns the parent of this node. + */ + XmlNode Parent() const; + /** + * Creates a new child element to this with name + */ + XmlNode CreateChildElement(const Aws::String& name); + /** + * Creates a new child element to this with name + */ + XmlNode CreateSiblingElement(const Aws::String& name); + /** + * If current node is valid. + */ + bool IsNull(); + + private: + XmlNode(Aws::External::tinyxml2::XMLNode* node, const XmlDocument& document) : + m_node(node), m_doc(&document) + { + } + + //we do not own these.... I just had to change it from ref because the compiler was + //confused about which assignment operator to call. Do not... I repeat... do not delete + //these pointers in your destructor. + Aws::External::tinyxml2::XMLNode* m_node; + const XmlDocument* m_doc; + + friend class XmlDocument; + }; + + /** + * Container for Xml Document as a whole. All nodes have a reference to their parent document. Any changes + * you make to the nodes will be reflected here. + */ + class AWS_CORE_API XmlDocument + { + public: + /** + * move document memory + */ + XmlDocument(const XmlDocument& other); + XmlDocument(XmlDocument&& doc); + + XmlDocument& operator=(const XmlDocument& other); + XmlDocument& operator=(XmlDocument&& other); + + ~XmlDocument(); + + /** + * Get root element of the document + */ + XmlNode GetRootElement() const; + /** + * Convert entire document to string. Use this if you for example, want to save the document to a file. + */ + Aws::String ConvertToString() const; + /** + * Returns true if the call to CreateFromXml* was successful, otherwise false. + * if this returns false, you can call GetErrorMessage() to see details. + */ + bool WasParseSuccessful() const; + /** + * Returns the error message if the call to CreateFromXml* failed. + */ + Aws::String GetErrorMessage() const; + /** + * Parses the stream into an XMLDocument + */ + static XmlDocument CreateFromXmlStream(Aws::IOStream&); + /** + * Parses the string into an XMLDocument + */ + static XmlDocument CreateFromXmlString(const Aws::String&); + /** + * Creates an empty document with root node name + */ + static XmlDocument CreateWithRootNode(const Aws::String&); + + private: + XmlDocument(); + void InitDoc(); + + Aws::External::tinyxml2::XMLDocument* m_doc; + + friend class XmlNode; + + //allow outcome call the default constructor to handle it's error case. + friend class Aws::Utils::Outcome<Aws::AmazonWebServiceResult<Aws::Utils::Xml::XmlDocument>, Aws::Client::AWSError<Aws::Client::CoreErrors>>; + friend class Aws::AmazonWebServiceResult<Aws::Utils::Xml::XmlDocument>; + template<typename T> + friend class Client::AWSError; + friend class Client::AWSXMLClient; + }; + + } // namespace Xml + } // namespace Utils +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/AmazonSerializableWebServiceRequest.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/AmazonSerializableWebServiceRequest.cpp new file mode 100644 index 0000000000..0c401b01b2 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/AmazonSerializableWebServiceRequest.cpp @@ -0,0 +1,24 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/AmazonSerializableWebServiceRequest.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> + +using namespace Aws; + +std::shared_ptr<Aws::IOStream> AmazonSerializableWebServiceRequest::GetBody() const +{ + Aws::String&& payload = SerializePayload(); + std::shared_ptr<Aws::IOStream> payloadBody; + + if (!payload.empty()) + { + payloadBody = Aws::MakeShared<Aws::StringStream>("AmazonSerializableWebServiceRequest"); + *payloadBody << payload; + } + + return payloadBody; +} + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/AmazonStreamingWebServiceRequest.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/AmazonStreamingWebServiceRequest.cpp new file mode 100644 index 0000000000..92e61c7ad4 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/AmazonStreamingWebServiceRequest.cpp @@ -0,0 +1,12 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/AmazonStreamingWebServiceRequest.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> + +using namespace Aws; + +AmazonStreamingWebServiceRequest::~AmazonStreamingWebServiceRequest() {} + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/AmazonWebServiceRequest.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/AmazonWebServiceRequest.cpp new file mode 100644 index 0000000000..a6b0406683 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/AmazonWebServiceRequest.cpp @@ -0,0 +1,20 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/AmazonWebServiceRequest.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> + +using namespace Aws; + +AmazonWebServiceRequest::AmazonWebServiceRequest() : + m_responseStreamFactory(Aws::Utils::Stream::DefaultResponseStreamFactoryMethod), + m_onDataReceived(nullptr), + m_onDataSent(nullptr), + m_continueRequest(nullptr), + m_onRequestSigned(nullptr), + m_requestRetryHandler(nullptr) +{ +} + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Aws.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Aws.cpp new file mode 100644 index 0000000000..1eaa477fca --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Aws.cpp @@ -0,0 +1,134 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include <aws/core/Version.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/Aws.h> +#include <aws/core/client/CoreErrors.h> +#include <aws/core/utils/logging/AWSLogging.h> +#include <aws/core/utils/logging/DefaultLogSystem.h> +#include <aws/core/Globals.h> +#include <aws/core/external/cjson/cJSON.h> +#include <aws/core/monitoring/MonitoringManager.h> +#include <aws/core/net/Net.h> +#include <aws/core/config/AWSProfileConfigLoader.h> +#include <aws/core/internal/AWSHttpResourceClient.h> + +namespace Aws +{ + static const char* ALLOCATION_TAG = "Aws_Init_Cleanup"; + + void InitAPI(const SDKOptions &options) + { +#ifdef USE_AWS_MEMORY_MANAGEMENT + if(options.memoryManagementOptions.memoryManager) + { + Aws::Utils::Memory::InitializeAWSMemorySystem(*options.memoryManagementOptions.memoryManager); + } +#endif // USE_AWS_MEMORY_MANAGEMENT + Aws::Client::CoreErrorsMapper::InitCoreErrorsMapper(); + if(options.loggingOptions.logLevel != Aws::Utils::Logging::LogLevel::Off) + { + if(options.loggingOptions.logger_create_fn) + { + Aws::Utils::Logging::InitializeAWSLogging(options.loggingOptions.logger_create_fn()); + } + else + { + Aws::Utils::Logging::InitializeAWSLogging( + Aws::MakeShared<Aws::Utils::Logging::DefaultLogSystem>(ALLOCATION_TAG, options.loggingOptions.logLevel, options.loggingOptions.defaultLogPrefix)); + } + // For users to better debugging in case multiple versions of SDK installed + AWS_LOGSTREAM_INFO(ALLOCATION_TAG, "Initiate AWS SDK for C++ with Version:" << Aws::String(Aws::Version::GetVersionString())); + } + + Aws::Config::InitConfigAndCredentialsCacheManager(); + + if (options.cryptoOptions.aes_CBCFactory_create_fn) + { + Aws::Utils::Crypto::SetAES_CBCFactory(options.cryptoOptions.aes_CBCFactory_create_fn()); + } + + if(options.cryptoOptions.aes_CTRFactory_create_fn) + { + Aws::Utils::Crypto::SetAES_CTRFactory(options.cryptoOptions.aes_CTRFactory_create_fn()); + } + + if(options.cryptoOptions.aes_GCMFactory_create_fn) + { + Aws::Utils::Crypto::SetAES_GCMFactory(options.cryptoOptions.aes_GCMFactory_create_fn()); + } + + if(options.cryptoOptions.md5Factory_create_fn) + { + Aws::Utils::Crypto::SetMD5Factory(options.cryptoOptions.md5Factory_create_fn()); + } + + if(options.cryptoOptions.sha256Factory_create_fn) + { + Aws::Utils::Crypto::SetSha256Factory(options.cryptoOptions.sha256Factory_create_fn()); + } + + if(options.cryptoOptions.sha256HMACFactory_create_fn) + { + Aws::Utils::Crypto::SetSha256HMACFactory(options.cryptoOptions.sha256HMACFactory_create_fn()); + } + + if (options.cryptoOptions.aes_KeyWrapFactory_create_fn) + { + Aws::Utils::Crypto::SetAES_KeyWrapFactory(options.cryptoOptions.aes_KeyWrapFactory_create_fn()); + } + + if(options.cryptoOptions.secureRandomFactory_create_fn) + { + Aws::Utils::Crypto::SetSecureRandomFactory(options.cryptoOptions.secureRandomFactory_create_fn()); + } + + Aws::Utils::Crypto::SetInitCleanupOpenSSLFlag(options.cryptoOptions.initAndCleanupOpenSSL); + Aws::Utils::Crypto::InitCrypto(); + + if(options.httpOptions.httpClientFactory_create_fn) + { + Aws::Http::SetHttpClientFactory(options.httpOptions.httpClientFactory_create_fn()); + } + + Aws::Http::SetInitCleanupCurlFlag(options.httpOptions.initAndCleanupCurl); + Aws::Http::SetInstallSigPipeHandlerFlag(options.httpOptions.installSigPipeHandler); + Aws::Http::InitHttp(); + Aws::InitializeEnumOverflowContainer(); + cJSON_Hooks hooks; + hooks.malloc_fn = [](size_t sz) { return Aws::Malloc("cJSON_Tag", sz); }; + hooks.free_fn = Aws::Free; + cJSON_InitHooks(&hooks); + Aws::Net::InitNetwork(); + Aws::Internal::InitEC2MetadataClient(); + Aws::Monitoring::InitMonitoring(options.monitoringOptions.customizedMonitoringFactory_create_fn); + } + + void ShutdownAPI(const SDKOptions& options) + { + Aws::Monitoring::CleanupMonitoring(); + Aws::Internal::CleanupEC2MetadataClient(); + Aws::Net::CleanupNetwork(); + Aws::CleanupEnumOverflowContainer(); + Aws::Http::CleanupHttp(); + Aws::Utils::Crypto::CleanupCrypto(); + + Aws::Config::CleanupConfigAndCredentialsCacheManager(); + + if(options.loggingOptions.logLevel != Aws::Utils::Logging::LogLevel::Off) + { + Aws::Utils::Logging::ShutdownAWSLogging(); + } + + Aws::Client::CoreErrorsMapper::CleanupCoreErrorsMapper(); + +#ifdef USE_AWS_MEMORY_MANAGEMENT + if(options.memoryManagementOptions.memoryManager) + { + Aws::Utils::Memory::ShutdownAWSMemorySystem(); + } +#endif // USE_AWS_MEMORY_MANAGEMENT + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Globals.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Globals.cpp new file mode 100644 index 0000000000..55f2ee9220 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Globals.cpp @@ -0,0 +1,28 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include <aws/core/Globals.h> +#include <aws/core/utils/EnumParseOverflowContainer.h> +#include <aws/core/utils/memory/AWSMemory.h> + +namespace Aws +{ + static const char TAG[] = "GlobalEnumOverflowContainer"; + static Utils::EnumParseOverflowContainer* g_enumOverflow; + + Utils::EnumParseOverflowContainer* GetEnumOverflowContainer() + { + return g_enumOverflow; + } + + void InitializeEnumOverflowContainer() + { + g_enumOverflow = Aws::New<Aws::Utils::EnumParseOverflowContainer>(TAG); + } + + void CleanupEnumOverflowContainer() + { + Aws::Delete(g_enumOverflow); + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Region.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Region.cpp new file mode 100644 index 0000000000..4b18bf2a2a --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Region.cpp @@ -0,0 +1,36 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/Region.h> +namespace Aws +{ + namespace Region + { + Aws::String ComputeSignerRegion(const Aws::String& region) + { + if (region == Aws::Region::AWS_GLOBAL) + { + return Aws::Region::US_EAST_1; + } + else if (region == "s3-external-1") + { + return Aws::Region::US_EAST_1; + } + else if (region.size() >= 5 && region.compare(0, 5, "fips-") == 0) + { + return region.substr(5); + } + else if (region.size() >= 5 && region.compare(region.size() - 5, 5, "-fips") == 0) + { + return region.substr(0, region.size() - 5); + } + else + { + return region; + } + } + } +}
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Version.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Version.cpp new file mode 100644 index 0000000000..35291906b7 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Version.cpp @@ -0,0 +1,53 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/Version.h> +#include <aws/core/VersionConfig.h> + +namespace Aws +{ +namespace Version +{ + const char* GetVersionString() + { + return AWS_SDK_VERSION_STRING; + } + + unsigned GetVersionMajor() + { + return AWS_SDK_VERSION_MAJOR; + } + + unsigned GetVersionMinor() + { + return AWS_SDK_VERSION_MINOR; + } + + unsigned GetVersionPatch() + { + return AWS_SDK_VERSION_PATCH; + } + + + const char* GetCompilerVersionString() + { +#define xstr(s) str(s) +#define str(s) #s +#if defined(_MSC_VER) + return "MSVC/" xstr(_MSC_VER); +#elif defined(__clang__) + return "Clang/" xstr(__clang_major__) "." xstr(__clang_minor__) "." xstr(__clang_patchlevel__); +#elif defined(__GNUC__) + return "GCC/" xstr(__GNUC__) "." xstr(__GNUC_MINOR__) "." xstr(__GNUC_PATCHLEVEL__); +#else + return "UnknownCompiler"; +#endif +#undef str +#undef xstr + } +} //namespace Version +} //namespace Aws + + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSAuthSigner.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSAuthSigner.cpp new file mode 100644 index 0000000000..de4826fa5b --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSAuthSigner.cpp @@ -0,0 +1,806 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/auth/AWSAuthSigner.h> + +#include <aws/core/auth/AWSCredentialsProvider.h> +#include <aws/core/client/ClientConfiguration.h> +#include <aws/core/http/HttpRequest.h> +#include <aws/core/http/HttpResponse.h> +#include <aws/core/utils/DateTime.h> +#include <aws/core/utils/HashingUtils.h> +#include <aws/core/utils/Outcome.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/memory/AWSMemory.h> +#include <aws/core/utils/crypto/Sha256.h> +#include <aws/core/utils/crypto/Sha256HMAC.h> +#include <aws/core/utils/stream/PreallocatedStreamBuf.h> +#include <aws/core/utils/event/EventMessage.h> +#include <aws/core/utils/event/EventHeader.h> + +#include <cstdio> +#include <iomanip> +#include <math.h> +#include <cstring> + +using namespace Aws; +using namespace Aws::Client; +using namespace Aws::Auth; +using namespace Aws::Http; +using namespace Aws::Utils; +using namespace Aws::Utils::Logging; + +static const char* EQ = "="; +static const char* AWS_HMAC_SHA256 = "AWS4-HMAC-SHA256"; +static const char* EVENT_STREAM_CONTENT_SHA256 = "STREAMING-AWS4-HMAC-SHA256-EVENTS"; +static const char* EVENT_STREAM_PAYLOAD = "AWS4-HMAC-SHA256-PAYLOAD"; +static const char* AWS4_REQUEST = "aws4_request"; +static const char* SIGNED_HEADERS = "SignedHeaders"; +static const char* CREDENTIAL = "Credential"; +static const char* NEWLINE = "\n"; +static const char* X_AMZ_SIGNED_HEADERS = "X-Amz-SignedHeaders"; +static const char* X_AMZ_ALGORITHM = "X-Amz-Algorithm"; +static const char* X_AMZ_CREDENTIAL = "X-Amz-Credential"; +static const char* UNSIGNED_PAYLOAD = "UNSIGNED-PAYLOAD"; +static const char* X_AMZ_SIGNATURE = "X-Amz-Signature"; +static const char* X_AMZN_TRACE_ID = "x-amzn-trace-id"; +static const char* X_AMZ_CONTENT_SHA256 = "x-amz-content-sha256"; +static const char* USER_AGENT = "user-agent"; +static const char* SIGNING_KEY = "AWS4"; +static const char* SIMPLE_DATE_FORMAT_STR = "%Y%m%d"; +static const char* EMPTY_STRING_SHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; + +static const char v4LogTag[] = "AWSAuthV4Signer"; +static const char v4StreamingLogTag[] = "AWSAuthEventStreamV4Signer"; + +namespace Aws +{ + namespace Auth + { + const char SIGNATURE[] = "Signature"; + const char SIGV4_SIGNER[] = "SignatureV4"; + const char EVENTSTREAM_SIGV4_SIGNER[] = "EventStreamSignatureV4"; + const char EVENTSTREAM_SIGNATURE_HEADER[] = ":chunk-signature"; + const char EVENTSTREAM_DATE_HEADER[] = ":date"; + const char NULL_SIGNER[] = "NullSigner"; + } +} + +static Aws::String CanonicalizeRequestSigningString(HttpRequest& request, bool urlEscapePath) +{ + request.CanonicalizeRequest(); + Aws::StringStream signingStringStream; + signingStringStream << HttpMethodMapper::GetNameForHttpMethod(request.GetMethod()); + + URI uriCpy = request.GetUri(); + // Many AWS services do not decode the URL before calculating SignatureV4 on their end. + // This results in the signature getting calculated with a double encoded URL. + // That means we have to double encode it here for the signature to match on the service side. + if(urlEscapePath) + { + // RFC3986 is how we encode the URL before sending it on the wire. + auto rfc3986EncodedPath = URI::URLEncodePathRFC3986(uriCpy.GetPath()); + uriCpy.SetPath(rfc3986EncodedPath); + // However, SignatureV4 uses this URL encoding scheme + signingStringStream << NEWLINE << uriCpy.GetURLEncodedPath() << NEWLINE; + } + else + { + // For the services that DO decode the URL first; we don't need to double encode it. + uriCpy.SetPath(uriCpy.GetURLEncodedPath()); + signingStringStream << NEWLINE << uriCpy.GetPath() << NEWLINE; + } + + if (request.GetQueryString().find('=') != std::string::npos) + { + signingStringStream << request.GetQueryString().substr(1) << NEWLINE; + } + else if (request.GetQueryString().size() > 1) + { + signingStringStream << request.GetQueryString().substr(1) << "=" << NEWLINE; + } + else + { + signingStringStream << NEWLINE; + } + + return signingStringStream.str(); +} + +static Http::HeaderValueCollection CanonicalizeHeaders(Http::HeaderValueCollection&& headers) +{ + Http::HeaderValueCollection canonicalHeaders; + for (const auto& header : headers) + { + auto trimmedHeaderName = StringUtils::Trim(header.first.c_str()); + auto trimmedHeaderValue = StringUtils::Trim(header.second.c_str()); + + //multiline gets converted to line1,line2,etc... + auto headerMultiLine = StringUtils::SplitOnLine(trimmedHeaderValue); + Aws::String headerValue = headerMultiLine.size() == 0 ? "" : headerMultiLine[0]; + + if (headerMultiLine.size() > 1) + { + for(size_t i = 1; i < headerMultiLine.size(); ++i) + { + headerValue += ","; + headerValue += StringUtils::Trim(headerMultiLine[i].c_str()); + } + } + + //duplicate spaces need to be converted to one. + Aws::String::iterator new_end = + std::unique(headerValue.begin(), headerValue.end(), + [=](char lhs, char rhs) { return (lhs == rhs) && (lhs == ' '); } + ); + headerValue.erase(new_end, headerValue.end()); + + canonicalHeaders[trimmedHeaderName] = headerValue; + } + + return canonicalHeaders; +} + +AWSAuthV4Signer::AWSAuthV4Signer(const std::shared_ptr<Auth::AWSCredentialsProvider>& credentialsProvider, + const char* serviceName, const Aws::String& region, PayloadSigningPolicy signingPolicy, bool urlEscapePath) : + m_includeSha256HashHeader(true), + m_credentialsProvider(credentialsProvider), + m_serviceName(serviceName), + m_region(region), + m_hash(Aws::MakeUnique<Aws::Utils::Crypto::Sha256>(v4LogTag)), + m_HMAC(Aws::MakeUnique<Aws::Utils::Crypto::Sha256HMAC>(v4LogTag)), + m_unsignedHeaders({USER_AGENT, X_AMZN_TRACE_ID}), + m_payloadSigningPolicy(signingPolicy), + m_urlEscapePath(urlEscapePath) +{ + //go ahead and warm up the signing cache. + ComputeHash(credentialsProvider->GetAWSCredentials().GetAWSSecretKey(), DateTime::CalculateGmtTimestampAsString(SIMPLE_DATE_FORMAT_STR), region, m_serviceName); +} + +AWSAuthV4Signer::~AWSAuthV4Signer() +{ + // empty destructor in .cpp file to keep from needing the implementation of (AWSCredentialsProvider, Sha256, Sha256HMAC) in the header file +} + + +bool AWSAuthV4Signer::ShouldSignHeader(const Aws::String& header) const +{ + return m_unsignedHeaders.find(Aws::Utils::StringUtils::ToLower(header.c_str())) == m_unsignedHeaders.cend(); +} + +bool AWSAuthV4Signer::SignRequest(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, bool signBody) const +{ + AWSCredentials credentials = m_credentialsProvider->GetAWSCredentials(); + + //don't sign anonymous requests + if (credentials.GetAWSAccessKeyId().empty() || credentials.GetAWSSecretKey().empty()) + { + return true; + } + + if (!credentials.GetSessionToken().empty()) + { + request.SetAwsSessionToken(credentials.GetSessionToken()); + } + + Aws::String payloadHash(UNSIGNED_PAYLOAD); + switch(m_payloadSigningPolicy) + { + case PayloadSigningPolicy::Always: + signBody = true; + break; + case PayloadSigningPolicy::Never: + signBody = false; + break; + case PayloadSigningPolicy::RequestDependent: + // respect the request setting + default: + break; + } + + if(signBody || request.GetUri().GetScheme() != Http::Scheme::HTTPS) + { + payloadHash = ComputePayloadHash(request); + if (payloadHash.empty()) + { + return false; + } + } + else + { + AWS_LOGSTREAM_DEBUG(v4LogTag, "Note: Http payloads are not being signed. signPayloads=" << signBody + << " http scheme=" << Http::SchemeMapper::ToString(request.GetUri().GetScheme())); + } + + if(m_includeSha256HashHeader) + { + request.SetHeaderValue(X_AMZ_CONTENT_SHA256, payloadHash); + } + + //calculate date header to use in internal signature (this also goes into date header). + DateTime now = GetSigningTimestamp(); + Aws::String dateHeaderValue = now.ToGmtString(DateFormat::ISO_8601_BASIC); + request.SetHeaderValue(AWS_DATE_HEADER, dateHeaderValue); + + Aws::StringStream headersStream; + Aws::StringStream signedHeadersStream; + + for (const auto& header : CanonicalizeHeaders(request.GetHeaders())) + { + if(ShouldSignHeader(header.first)) + { + headersStream << header.first.c_str() << ":" << header.second.c_str() << NEWLINE; + signedHeadersStream << header.first.c_str() << ";"; + } + } + + Aws::String canonicalHeadersString = headersStream.str(); + AWS_LOGSTREAM_DEBUG(v4LogTag, "Canonical Header String: " << canonicalHeadersString); + + //calculate signed headers parameter + Aws::String signedHeadersValue = signedHeadersStream.str(); + //remove that last semi-colon + if (!signedHeadersValue.empty()) + { + signedHeadersValue.pop_back(); + } + + AWS_LOGSTREAM_DEBUG(v4LogTag, "Signed Headers value:" << signedHeadersValue); + + //generate generalized canonicalized request string. + Aws::String canonicalRequestString = CanonicalizeRequestSigningString(request, m_urlEscapePath); + + //append v4 stuff to the canonical request string. + canonicalRequestString.append(canonicalHeadersString); + canonicalRequestString.append(NEWLINE); + canonicalRequestString.append(signedHeadersValue); + canonicalRequestString.append(NEWLINE); + canonicalRequestString.append(payloadHash); + + AWS_LOGSTREAM_DEBUG(v4LogTag, "Canonical Request String: " << canonicalRequestString); + + //now compute sha256 on that request string + auto hashResult = m_hash->Calculate(canonicalRequestString); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4LogTag, "Failed to hash (sha256) request string"); + AWS_LOGSTREAM_DEBUG(v4LogTag, "The request string is: \"" << canonicalRequestString << "\""); + return false; + } + + auto sha256Digest = hashResult.GetResult(); + Aws::String canonicalRequestHash = HashingUtils::HexEncode(sha256Digest); + Aws::String simpleDate = now.ToGmtString(SIMPLE_DATE_FORMAT_STR); + + Aws::String signingRegion = region ? region : m_region; + Aws::String signingServiceName = serviceName ? serviceName : m_serviceName; + Aws::String stringToSign = GenerateStringToSign(dateHeaderValue, simpleDate, canonicalRequestHash, signingRegion, signingServiceName); + auto finalSignature = GenerateSignature(credentials, stringToSign, simpleDate, signingRegion, signingServiceName); + + Aws::StringStream ss; + ss << AWS_HMAC_SHA256 << " " << CREDENTIAL << EQ << credentials.GetAWSAccessKeyId() << "/" << simpleDate + << "/" << signingRegion << "/" << signingServiceName << "/" << AWS4_REQUEST << ", " << SIGNED_HEADERS << EQ + << signedHeadersValue << ", " << SIGNATURE << EQ << finalSignature; + + auto awsAuthString = ss.str(); + AWS_LOGSTREAM_DEBUG(v4LogTag, "Signing request with: " << awsAuthString); + request.SetAwsAuthorization(awsAuthString); + request.SetSigningAccessKey(credentials.GetAWSAccessKeyId()); + request.SetSigningRegion(signingRegion); + return true; +} + +bool AWSAuthV4Signer::PresignRequest(Aws::Http::HttpRequest& request, long long expirationTimeInSeconds) const +{ + return PresignRequest(request, m_region.c_str(), expirationTimeInSeconds); +} + +bool AWSAuthV4Signer::PresignRequest(Aws::Http::HttpRequest& request, const char* region, long long expirationInSeconds) const +{ + return PresignRequest(request, region, m_serviceName.c_str(), expirationInSeconds); +} + +bool AWSAuthV4Signer::PresignRequest(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, long long expirationTimeInSeconds) const +{ + AWSCredentials credentials = m_credentialsProvider->GetAWSCredentials(); + + //don't sign anonymous requests + if (credentials.GetAWSAccessKeyId().empty() || credentials.GetAWSSecretKey().empty()) + { + return true; + } + + Aws::StringStream intConversionStream; + intConversionStream << expirationTimeInSeconds; + request.AddQueryStringParameter(Http::X_AMZ_EXPIRES_HEADER, intConversionStream.str()); + + if (!credentials.GetSessionToken().empty()) + { + request.AddQueryStringParameter(Http::AWS_SECURITY_TOKEN, credentials.GetSessionToken()); + } + + //calculate date header to use in internal signature (this also goes into date header). + DateTime now = GetSigningTimestamp(); + Aws::String dateQueryValue = now.ToGmtString(DateFormat::ISO_8601_BASIC); + request.AddQueryStringParameter(Http::AWS_DATE_HEADER, dateQueryValue); + + Aws::StringStream headersStream; + Aws::StringStream signedHeadersStream; + for (const auto& header : CanonicalizeHeaders(request.GetHeaders())) + { + if(ShouldSignHeader(header.first)) + { + headersStream << header.first.c_str() << ":" << header.second.c_str() << NEWLINE; + signedHeadersStream << header.first.c_str() << ";"; + } + } + + Aws::String canonicalHeadersString = headersStream.str(); + AWS_LOGSTREAM_DEBUG(v4LogTag, "Canonical Header String: " << canonicalHeadersString); + + //calculate signed headers parameter + Aws::String signedHeadersValue(signedHeadersStream.str()); + //remove that last semi-colon + if (!signedHeadersValue.empty()) + { + signedHeadersValue.pop_back(); + } + + request.AddQueryStringParameter(X_AMZ_SIGNED_HEADERS, signedHeadersValue); + AWS_LOGSTREAM_DEBUG(v4LogTag, "Signed Headers value: " << signedHeadersValue); + + Aws::StringStream ss; + Aws::String signingRegion = region ? region : m_region; + Aws::String signingServiceName = serviceName ? serviceName : m_serviceName; + Aws::String simpleDate = now.ToGmtString(SIMPLE_DATE_FORMAT_STR); + ss << credentials.GetAWSAccessKeyId() << "/" << simpleDate + << "/" << signingRegion << "/" << signingServiceName << "/" << AWS4_REQUEST; + + request.AddQueryStringParameter(X_AMZ_ALGORITHM, AWS_HMAC_SHA256); + request.AddQueryStringParameter(X_AMZ_CREDENTIAL, ss.str()); + ss.str(""); + + request.SetSigningAccessKey(credentials.GetAWSAccessKeyId()); + request.SetSigningRegion(signingRegion); + + //generate generalized canonicalized request string. + Aws::String canonicalRequestString = CanonicalizeRequestSigningString(request, m_urlEscapePath); + + //append v4 stuff to the canonical request string. + canonicalRequestString.append(canonicalHeadersString); + canonicalRequestString.append(NEWLINE); + canonicalRequestString.append(signedHeadersValue); + canonicalRequestString.append(NEWLINE); + if (ServiceRequireUnsignedPayload(signingServiceName)) + { + canonicalRequestString.append(UNSIGNED_PAYLOAD); + } + else + { + canonicalRequestString.append(EMPTY_STRING_SHA256); + } + AWS_LOGSTREAM_DEBUG(v4LogTag, "Canonical Request String: " << canonicalRequestString); + + //now compute sha256 on that request string + auto hashResult = m_hash->Calculate(canonicalRequestString); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4LogTag, "Failed to hash (sha256) request string"); + AWS_LOGSTREAM_DEBUG(v4LogTag, "The request string is: \"" << canonicalRequestString << "\""); + return false; + } + + auto sha256Digest = hashResult.GetResult(); + auto canonicalRequestHash = HashingUtils::HexEncode(sha256Digest); + + auto stringToSign = GenerateStringToSign(dateQueryValue, simpleDate, canonicalRequestHash, signingRegion, signingServiceName); + auto finalSigningHash = GenerateSignature(credentials, stringToSign, simpleDate, signingRegion, signingServiceName); + if (finalSigningHash.empty()) + { + return false; + } + + //add that the signature to the query string + request.AddQueryStringParameter(X_AMZ_SIGNATURE, finalSigningHash); + + return true; +} + +bool AWSAuthV4Signer::ServiceRequireUnsignedPayload(const Aws::String& serviceName) const +{ + // S3 uses a magic string (instead of the empty string) for its body hash for presigned URLs as outlined here: + // https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html + // this is true for PUT, POST, GET, DELETE and HEAD operations. + // However, other services (for example RDS) implement the specification as outlined here: + // https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html + // which states that body-less requests should use the empty-string SHA256 hash. + return "s3" == serviceName; +} + +Aws::String AWSAuthV4Signer::GenerateSignature(const AWSCredentials& credentials, const Aws::String& stringToSign, + const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const +{ + auto key = ComputeHash(credentials.GetAWSSecretKey(), simpleDate, region, serviceName); + return GenerateSignature(stringToSign, key); +} + +Aws::String AWSAuthV4Signer::GenerateSignature(const Aws::String& stringToSign, const ByteBuffer& key) const +{ + AWS_LOGSTREAM_DEBUG(v4LogTag, "Final String to sign: " << stringToSign); + + Aws::StringStream ss; + + auto hashResult = m_HMAC->Calculate(ByteBuffer((unsigned char*)stringToSign.c_str(), stringToSign.length()), key); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4LogTag, "Unable to hmac (sha256) final string"); + AWS_LOGSTREAM_DEBUG(v4LogTag, "The final string is: \"" << stringToSign << "\""); + return {}; + } + + //now we finally sign our request string with our hex encoded derived hash. + auto finalSigningDigest = hashResult.GetResult(); + + auto finalSigningHash = HashingUtils::HexEncode(finalSigningDigest); + AWS_LOGSTREAM_DEBUG(v4LogTag, "Final computed signing hash: " << finalSigningHash); + + return finalSigningHash; +} + +Aws::String AWSAuthV4Signer::ComputePayloadHash(Aws::Http::HttpRequest& request) const +{ + if (!request.GetContentBody()) + { + AWS_LOGSTREAM_DEBUG(v4LogTag, "Using cached empty string sha256 " << EMPTY_STRING_SHA256 << " because payload is empty."); + return EMPTY_STRING_SHA256; + } + + //compute hash on payload if it exists. + auto hashResult = m_hash->Calculate(*request.GetContentBody()); + + if(request.GetContentBody()) + { + request.GetContentBody()->clear(); + request.GetContentBody()->seekg(0); + } + + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4LogTag, "Unable to hash (sha256) request body"); + return {}; + } + + auto sha256Digest = hashResult.GetResult(); + + Aws::String payloadHash(HashingUtils::HexEncode(sha256Digest)); + AWS_LOGSTREAM_DEBUG(v4LogTag, "Calculated sha256 " << payloadHash << " for payload."); + return payloadHash; +} + +Aws::String AWSAuthV4Signer::GenerateStringToSign(const Aws::String& dateValue, const Aws::String& simpleDate, + const Aws::String& canonicalRequestHash, const Aws::String& region, const Aws::String& serviceName) const +{ + //generate the actual string we will use in signing the final request. + Aws::StringStream ss; + + ss << AWS_HMAC_SHA256 << NEWLINE << dateValue << NEWLINE << simpleDate << "/" << region << "/" + << serviceName << "/" << AWS4_REQUEST << NEWLINE << canonicalRequestHash; + + return ss.str(); +} + +Aws::Utils::ByteBuffer AWSAuthV4Signer::ComputeHash(const Aws::String& secretKey, + const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const +{ + Aws::String signingKey(SIGNING_KEY); + signingKey.append(secretKey); + auto hashResult = m_HMAC->Calculate(ByteBuffer((unsigned char*)simpleDate.c_str(), simpleDate.length()), + ByteBuffer((unsigned char*)signingKey.c_str(), signingKey.length())); + + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4LogTag, "Failed to HMAC (SHA256) date string \"" << simpleDate << "\""); + return {}; + } + + auto kDate = hashResult.GetResult(); + hashResult = m_HMAC->Calculate(ByteBuffer((unsigned char*)region.c_str(), region.length()), kDate); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4LogTag, "Failed to HMAC (SHA256) region string \"" << region << "\""); + return {}; + } + + auto kRegion = hashResult.GetResult(); + hashResult = m_HMAC->Calculate(ByteBuffer((unsigned char*)serviceName.c_str(), serviceName.length()), kRegion); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4LogTag, "Failed to HMAC (SHA256) service string \"" << m_serviceName << "\""); + return {}; + } + + auto kService = hashResult.GetResult(); + hashResult = m_HMAC->Calculate(ByteBuffer((unsigned char*)AWS4_REQUEST, strlen(AWS4_REQUEST)), kService); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4LogTag, "Unable to HMAC (SHA256) request string"); + AWS_LOGSTREAM_DEBUG(v4LogTag, "The request string is: \"" << AWS4_REQUEST << "\""); + return {}; + } + return hashResult.GetResult(); +} + +AWSAuthEventStreamV4Signer::AWSAuthEventStreamV4Signer(const std::shared_ptr<Auth::AWSCredentialsProvider>& + credentialsProvider, const char* serviceName, const Aws::String& region) : + m_serviceName(serviceName), + m_region(region), + m_credentialsProvider(credentialsProvider) +{ + + m_unsignedHeaders.emplace_back(X_AMZN_TRACE_ID); + m_unsignedHeaders.emplace_back(USER_AGENT_HEADER); +} + +bool AWSAuthEventStreamV4Signer::SignRequest(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, bool /* signBody */) const +{ + AWSCredentials credentials = m_credentialsProvider->GetAWSCredentials(); + + //don't sign anonymous requests + if (credentials.GetAWSAccessKeyId().empty() || credentials.GetAWSSecretKey().empty()) + { + return true; + } + + if (!credentials.GetSessionToken().empty()) + { + request.SetAwsSessionToken(credentials.GetSessionToken()); + } + + request.SetHeaderValue(X_AMZ_CONTENT_SHA256, EVENT_STREAM_CONTENT_SHA256); + + //calculate date header to use in internal signature (this also goes into date header). + DateTime now = GetSigningTimestamp(); + Aws::String dateHeaderValue = now.ToGmtString(DateFormat::ISO_8601_BASIC); + request.SetHeaderValue(AWS_DATE_HEADER, dateHeaderValue); + + Aws::StringStream headersStream; + Aws::StringStream signedHeadersStream; + + for (const auto& header : CanonicalizeHeaders(request.GetHeaders())) + { + if(ShouldSignHeader(header.first)) + { + headersStream << header.first.c_str() << ":" << header.second.c_str() << NEWLINE; + signedHeadersStream << header.first.c_str() << ";"; + } + } + + Aws::String canonicalHeadersString = headersStream.str(); + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Canonical Header String: " << canonicalHeadersString); + + //calculate signed headers parameter + Aws::String signedHeadersValue = signedHeadersStream.str(); + //remove that last semi-colon + if (!signedHeadersValue.empty()) + { + signedHeadersValue.pop_back(); + } + + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Signed Headers value:" << signedHeadersValue); + + //generate generalized canonicalized request string. + Aws::String canonicalRequestString = CanonicalizeRequestSigningString(request, true/* m_urlEscapePath */); + + //append v4 stuff to the canonical request string. + canonicalRequestString.append(canonicalHeadersString); + canonicalRequestString.append(NEWLINE); + canonicalRequestString.append(signedHeadersValue); + canonicalRequestString.append(NEWLINE); + canonicalRequestString.append(EVENT_STREAM_CONTENT_SHA256); + + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Canonical Request String: " << canonicalRequestString); + + //now compute sha256 on that request string + auto hashResult = m_hash.Calculate(canonicalRequestString); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to hash (sha256) request string"); + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "The request string is: \"" << canonicalRequestString << "\""); + return false; + } + + auto sha256Digest = hashResult.GetResult(); + Aws::String canonicalRequestHash = HashingUtils::HexEncode(sha256Digest); + Aws::String simpleDate = now.ToGmtString(SIMPLE_DATE_FORMAT_STR); + + Aws::String signingRegion = region ? region : m_region; + Aws::String signingServiceName = serviceName ? serviceName : m_serviceName; + Aws::String stringToSign = GenerateStringToSign(dateHeaderValue, simpleDate, canonicalRequestHash, signingRegion, signingServiceName); + auto finalSignature = GenerateSignature(credentials, stringToSign, simpleDate, signingRegion, signingServiceName); + + Aws::StringStream ss; + ss << AWS_HMAC_SHA256 << " " << CREDENTIAL << EQ << credentials.GetAWSAccessKeyId() << "/" << simpleDate + << "/" << signingRegion << "/" << signingServiceName << "/" << AWS4_REQUEST << ", " << SIGNED_HEADERS << EQ + << signedHeadersValue << ", " << SIGNATURE << EQ << HashingUtils::HexEncode(finalSignature); + + auto awsAuthString = ss.str(); + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Signing request with: " << awsAuthString); + request.SetAwsAuthorization(awsAuthString); + request.SetSigningAccessKey(credentials.GetAWSAccessKeyId()); + request.SetSigningRegion(signingRegion); + return true; +} + +// this works regardless if the current machine is Big/Little Endian +static void WriteBigEndian(Aws::String& str, uint64_t n) +{ + int shift = 56; + while(shift >= 0) + { + str.push_back((n >> shift) & 0xFF); + shift -= 8; + } +} + +bool AWSAuthEventStreamV4Signer::SignEventMessage(Event::Message& message, Aws::String& priorSignature) const +{ + using Event::EventHeaderValue; + + Aws::StringStream stringToSign; + stringToSign << EVENT_STREAM_PAYLOAD << NEWLINE; + const DateTime now = GetSigningTimestamp(); + const auto simpleDate = now.ToGmtString(SIMPLE_DATE_FORMAT_STR); + stringToSign << now.ToGmtString(DateFormat::ISO_8601_BASIC) << NEWLINE + << simpleDate << "/" << m_region << "/" + << m_serviceName << "/aws4_request" << NEWLINE << priorSignature << NEWLINE; + + + Aws::String nonSignatureHeaders; + nonSignatureHeaders.push_back(char(sizeof(EVENTSTREAM_DATE_HEADER) - 1)); // length of the string + nonSignatureHeaders += EVENTSTREAM_DATE_HEADER; + nonSignatureHeaders.push_back(static_cast<char>(EventHeaderValue::EventHeaderType::TIMESTAMP)); // type of the value + WriteBigEndian(nonSignatureHeaders, static_cast<uint64_t>(now.Millis())); // the value of the timestamp in big-endian + + auto hashOutcome = m_hash.Calculate(nonSignatureHeaders); + if (!hashOutcome.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to hash (sha256) non-signature headers."); + return false; + } + + const auto nonSignatureHeadersHash = hashOutcome.GetResult(); + stringToSign << HashingUtils::HexEncode(nonSignatureHeadersHash) << NEWLINE; + + if (message.GetEventPayload().empty()) + { + AWS_LOGSTREAM_WARN(v4StreamingLogTag, "Attempting to sign an empty message (no payload and no headers). " + "It is unlikely that this is the intended behavior."); + } + else + { + // use a preallocatedStreamBuf to avoid making a copy. + // The Hashing API requires either Aws::String or IStream as input. + // TODO: the hashing API should be accept 'unsigned char*' as input. + Utils::Stream::PreallocatedStreamBuf streamBuf(message.GetEventPayload().data(), message.GetEventPayload().size()); + Aws::IOStream payload(&streamBuf); + hashOutcome = m_hash.Calculate(payload); + + if (!hashOutcome.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to hash (sha256) non-signature headers."); + return false; + } + const auto payloadHash = hashOutcome.GetResult(); + stringToSign << HashingUtils::HexEncode(payloadHash); + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Payload hash - " << HashingUtils::HexEncode(payloadHash)); + } + + Utils::ByteBuffer finalSignatureDigest = GenerateSignature(m_credentialsProvider->GetAWSCredentials(), stringToSign.str(), simpleDate, m_region, m_serviceName); + const auto finalSignature = HashingUtils::HexEncode(finalSignatureDigest); + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Final computed signing hash: " << finalSignature); + priorSignature = finalSignature; + + message.InsertEventHeader(EVENTSTREAM_DATE_HEADER, EventHeaderValue(now.Millis(), EventHeaderValue::EventHeaderType::TIMESTAMP)); + message.InsertEventHeader(EVENTSTREAM_SIGNATURE_HEADER, std::move(finalSignatureDigest)); + + AWS_LOGSTREAM_INFO(v4StreamingLogTag, "Event chunk final signature - " << finalSignature); + return true; +} + +bool AWSAuthEventStreamV4Signer::ShouldSignHeader(const Aws::String& header) const +{ + return std::find(m_unsignedHeaders.cbegin(), m_unsignedHeaders.cend(), Aws::Utils::StringUtils::ToLower(header.c_str())) == m_unsignedHeaders.cend(); +} + +Utils::ByteBuffer AWSAuthEventStreamV4Signer::GenerateSignature(const AWSCredentials& credentials, const Aws::String& stringToSign, + const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const +{ + Utils::Threading::ReaderLockGuard guard(m_derivedKeyLock); + const auto& secretKey = credentials.GetAWSSecretKey(); + if (secretKey != m_currentSecretKey || simpleDate != m_currentDateStr) + { + guard.UpgradeToWriterLock(); + // double-checked lock to prevent updating twice + if (m_currentDateStr != simpleDate || m_currentSecretKey != secretKey) + { + m_currentSecretKey = secretKey; + m_currentDateStr = simpleDate; + m_derivedKey = ComputeHash(m_currentSecretKey, m_currentDateStr, region, serviceName); + } + + } + return GenerateSignature(stringToSign, m_derivedKey); +} + +Utils::ByteBuffer AWSAuthEventStreamV4Signer::GenerateSignature(const Aws::String& stringToSign, const ByteBuffer& key) const +{ + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Final String to sign: " << stringToSign); + + Aws::StringStream ss; + + auto hashResult = m_HMAC.Calculate(ByteBuffer((unsigned char*)stringToSign.c_str(), stringToSign.length()), key); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Unable to hmac (sha256) final string"); + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "The final string is: \"" << stringToSign << "\""); + return {}; + } + + return hashResult.GetResult(); +} + +Aws::String AWSAuthEventStreamV4Signer::GenerateStringToSign(const Aws::String& dateValue, const Aws::String& simpleDate, + const Aws::String& canonicalRequestHash, const Aws::String& region, const Aws::String& serviceName) const +{ + //generate the actual string we will use in signing the final request. + Aws::StringStream ss; + + ss << AWS_HMAC_SHA256 << NEWLINE << dateValue << NEWLINE << simpleDate << "/" << region << "/" + << serviceName << "/" << AWS4_REQUEST << NEWLINE << canonicalRequestHash; + + return ss.str(); +} + +Aws::Utils::ByteBuffer AWSAuthEventStreamV4Signer::ComputeHash(const Aws::String& secretKey, + const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const +{ + Aws::String signingKey(SIGNING_KEY); + signingKey.append(secretKey); + auto hashResult = m_HMAC.Calculate(ByteBuffer((unsigned char*)simpleDate.c_str(), simpleDate.length()), + ByteBuffer((unsigned char*)signingKey.c_str(), signingKey.length())); + + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to HMAC (SHA256) date string \"" << simpleDate << "\""); + return {}; + } + + auto kDate = hashResult.GetResult(); + hashResult = m_HMAC.Calculate(ByteBuffer((unsigned char*)region.c_str(), region.length()), kDate); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to HMAC (SHA256) region string \"" << region << "\""); + return {}; + } + + auto kRegion = hashResult.GetResult(); + hashResult = m_HMAC.Calculate(ByteBuffer((unsigned char*)serviceName.c_str(), serviceName.length()), kRegion); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to HMAC (SHA256) service string \"" << m_serviceName << "\""); + return {}; + } + + auto kService = hashResult.GetResult(); + hashResult = m_HMAC.Calculate(ByteBuffer((unsigned char*)AWS4_REQUEST, strlen(AWS4_REQUEST)), kService); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Unable to HMAC (SHA256) request string"); + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "The request string is: \"" << AWS4_REQUEST << "\""); + return {}; + } + return hashResult.GetResult(); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSAuthSignerProvider.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSAuthSignerProvider.cpp new file mode 100644 index 0000000000..31fd6c006b --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSAuthSignerProvider.cpp @@ -0,0 +1,51 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/auth/AWSAuthSignerProvider.h> +#include <aws/core/auth/AWSAuthSigner.h> +#include <aws/core/auth/AWSCredentialsProvider.h> +#include <aws/core/utils/memory/stl/AWSAllocator.h> + +const char CLASS_TAG[] = "AuthSignerProvider"; + +using namespace Aws::Auth; + +DefaultAuthSignerProvider::DefaultAuthSignerProvider(const std::shared_ptr<AWSCredentialsProvider>& credentialsProvider, + const Aws::String& serviceName, const Aws::String& region) +{ + m_signers.emplace_back(Aws::MakeShared<Aws::Client::AWSAuthV4Signer>(CLASS_TAG, credentialsProvider, serviceName.c_str(), region)); + m_signers.emplace_back(Aws::MakeShared<Aws::Client::AWSAuthEventStreamV4Signer>(CLASS_TAG, credentialsProvider, serviceName.c_str(), region)); + m_signers.emplace_back(Aws::MakeShared<Aws::Client::AWSNullSigner>(CLASS_TAG)); +} + +DefaultAuthSignerProvider::DefaultAuthSignerProvider(const std::shared_ptr<Aws::Client::AWSAuthSigner>& signer) +{ + m_signers.emplace_back(Aws::MakeShared<Aws::Client::AWSNullSigner>(CLASS_TAG)); + if(signer) + { + m_signers.emplace_back(signer); + } +} + +std::shared_ptr<Aws::Client::AWSAuthSigner> DefaultAuthSignerProvider::GetSigner(const Aws::String& signerName) const +{ + for(const auto& signer : m_signers) + { + if(signer->GetName() == signerName) + { + return signer; + } + } + AWS_LOGSTREAM_ERROR(CLASS_TAG, "Request's signer: '" << signerName << "' is not found in the signer's map."); + assert(false); + return nullptr; +} + +void DefaultAuthSignerProvider::AddSigner(std::shared_ptr<Aws::Client::AWSAuthSigner>& signer) +{ + assert(signer); + m_signers.emplace_back(signer); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSCredentialsProvider.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSCredentialsProvider.cpp new file mode 100644 index 0000000000..31e28b996f --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSCredentialsProvider.cpp @@ -0,0 +1,466 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#include <aws/core/auth/AWSCredentialsProvider.h> + +#include <aws/core/config/AWSProfileConfigLoader.h> +#include <aws/core/platform/Environment.h> +#include <aws/core/platform/FileSystem.h> +#include <aws/core/platform/OSVersionInfo.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/json/JsonSerializer.h> +#include <aws/core/utils/FileSystemUtils.h> +#include <aws/core/client/AWSError.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/xml/XmlSerializer.h> +#include <cstdlib> +#include <fstream> +#include <string.h> +#include <climits> + + +using namespace Aws::Utils; +using namespace Aws::Utils::Logging; +using namespace Aws::Auth; +using namespace Aws::Internal; +using namespace Aws::FileSystem; +using namespace Aws::Utils::Xml; +using namespace Aws::Client; +using Aws::Utils::Threading::ReaderLockGuard; +using Aws::Utils::Threading::WriterLockGuard; + +static const char ACCESS_KEY_ENV_VAR[] = "AWS_ACCESS_KEY_ID"; +static const char SECRET_KEY_ENV_VAR[] = "AWS_SECRET_ACCESS_KEY"; +static const char SESSION_TOKEN_ENV_VAR[] = "AWS_SESSION_TOKEN"; +static const char DEFAULT_PROFILE[] = "default"; +static const char AWS_PROFILE_ENV_VAR[] = "AWS_PROFILE"; +static const char AWS_PROFILE_DEFAULT_ENV_VAR[] = "AWS_DEFAULT_PROFILE"; + +static const char AWS_CREDENTIALS_FILE[] = "AWS_SHARED_CREDENTIALS_FILE"; +extern const char AWS_CONFIG_FILE[] = "AWS_CONFIG_FILE"; + +extern const char PROFILE_DIRECTORY[] = ".aws"; +static const char DEFAULT_CREDENTIALS_FILE[] = "credentials"; +extern const char DEFAULT_CONFIG_FILE[] = "config"; + + +static const int EXPIRATION_GRACE_PERIOD = 5 * 1000; + +void AWSCredentialsProvider::Reload() +{ + m_lastLoadedMs = DateTime::Now().Millis(); +} + +bool AWSCredentialsProvider::IsTimeToRefresh(long reloadFrequency) +{ + if (DateTime::Now().Millis() - m_lastLoadedMs > reloadFrequency) + { + return true; + } + return false; +} + + +static const char* ENVIRONMENT_LOG_TAG = "EnvironmentAWSCredentialsProvider"; + + +AWSCredentials EnvironmentAWSCredentialsProvider::GetAWSCredentials() +{ + auto accessKey = Aws::Environment::GetEnv(ACCESS_KEY_ENV_VAR); + AWSCredentials credentials; + + if (!accessKey.empty()) + { + credentials.SetAWSAccessKeyId(accessKey); + + AWS_LOGSTREAM_DEBUG(ENVIRONMENT_LOG_TAG, "Found credential in environment with access key id " << accessKey); + auto secretKey = Aws::Environment::GetEnv(SECRET_KEY_ENV_VAR); + + if (!secretKey.empty()) + { + credentials.SetAWSSecretKey(secretKey); + AWS_LOGSTREAM_INFO(ENVIRONMENT_LOG_TAG, "Found secret key"); + } + + auto sessionToken = Aws::Environment::GetEnv(SESSION_TOKEN_ENV_VAR); + + if(!sessionToken.empty()) + { + credentials.SetSessionToken(sessionToken); + AWS_LOGSTREAM_INFO(ENVIRONMENT_LOG_TAG, "Found sessionToken"); + } + } + + return credentials; +} + +Aws::String Aws::Auth::GetConfigProfileFilename() +{ + auto configFileNameFromVar = Aws::Environment::GetEnv(AWS_CONFIG_FILE); + if (!configFileNameFromVar.empty()) + { + return configFileNameFromVar; + } + else + { + return Aws::FileSystem::GetHomeDirectory() + PROFILE_DIRECTORY + PATH_DELIM + DEFAULT_CONFIG_FILE; + } +} + +Aws::String Aws::Auth::GetConfigProfileName() +{ + auto profileFromVar = Aws::Environment::GetEnv(AWS_PROFILE_DEFAULT_ENV_VAR); + if (profileFromVar.empty()) + { + profileFromVar = Aws::Environment::GetEnv(AWS_PROFILE_ENV_VAR); + } + + if (profileFromVar.empty()) + { + return Aws::String(DEFAULT_PROFILE); + } + else + { + return profileFromVar; + } +} + +static const char* PROFILE_LOG_TAG = "ProfileConfigFileAWSCredentialsProvider"; + +Aws::String ProfileConfigFileAWSCredentialsProvider::GetCredentialsProfileFilename() +{ + auto credentialsFileNameFromVar = Aws::Environment::GetEnv(AWS_CREDENTIALS_FILE); + + if (credentialsFileNameFromVar.empty()) + { + return Aws::FileSystem::GetHomeDirectory() + PROFILE_DIRECTORY + PATH_DELIM + DEFAULT_CREDENTIALS_FILE; + } + else + { + return credentialsFileNameFromVar; + } +} + +Aws::String ProfileConfigFileAWSCredentialsProvider::GetProfileDirectory() +{ + Aws::String credentialsFileName = GetCredentialsProfileFilename(); + auto lastSeparator = credentialsFileName.find_last_of(PATH_DELIM); + if (lastSeparator != std::string::npos) + { + return credentialsFileName.substr(0, lastSeparator); + } + else + { + return {}; + } +} + +ProfileConfigFileAWSCredentialsProvider::ProfileConfigFileAWSCredentialsProvider(long refreshRateMs) : + m_profileToUse(Aws::Auth::GetConfigProfileName()), + m_credentialsFileLoader(GetCredentialsProfileFilename()), + m_loadFrequencyMs(refreshRateMs) +{ + AWS_LOGSTREAM_INFO(PROFILE_LOG_TAG, "Setting provider to read credentials from " << GetCredentialsProfileFilename() << " for credentials file" + << " and " << GetConfigProfileFilename() << " for the config file " + << ", for use with profile " << m_profileToUse); +} + +ProfileConfigFileAWSCredentialsProvider::ProfileConfigFileAWSCredentialsProvider(const char* profile, long refreshRateMs) : + m_profileToUse(profile), + m_credentialsFileLoader(GetCredentialsProfileFilename()), + m_loadFrequencyMs(refreshRateMs) +{ + AWS_LOGSTREAM_INFO(PROFILE_LOG_TAG, "Setting provider to read credentials from " << GetCredentialsProfileFilename() << " for credentials file" + << " and " << GetConfigProfileFilename() << " for the config file " + << ", for use with profile " << m_profileToUse); +} + +AWSCredentials ProfileConfigFileAWSCredentialsProvider::GetAWSCredentials() +{ + RefreshIfExpired(); + ReaderLockGuard guard(m_reloadLock); + auto credsFileProfileIter = m_credentialsFileLoader.GetProfiles().find(m_profileToUse); + + if(credsFileProfileIter != m_credentialsFileLoader.GetProfiles().end()) + { + return credsFileProfileIter->second.GetCredentials(); + } + + return AWSCredentials(); +} + + +void ProfileConfigFileAWSCredentialsProvider::Reload() +{ + m_credentialsFileLoader.Load(); + AWSCredentialsProvider::Reload(); +} + +void ProfileConfigFileAWSCredentialsProvider::RefreshIfExpired() +{ + ReaderLockGuard guard(m_reloadLock); + if (!IsTimeToRefresh(m_loadFrequencyMs)) + { + return; + } + + guard.UpgradeToWriterLock(); + if (!IsTimeToRefresh(m_loadFrequencyMs)) // double-checked lock to avoid refreshing twice + { + return; + } + + Reload(); +} + +static const char* INSTANCE_LOG_TAG = "InstanceProfileCredentialsProvider"; + +InstanceProfileCredentialsProvider::InstanceProfileCredentialsProvider(long refreshRateMs) : + m_ec2MetadataConfigLoader(Aws::MakeShared<Aws::Config::EC2InstanceProfileConfigLoader>(INSTANCE_LOG_TAG)), + m_loadFrequencyMs(refreshRateMs) +{ + AWS_LOGSTREAM_INFO(INSTANCE_LOG_TAG, "Creating Instance with default EC2MetadataClient and refresh rate " << refreshRateMs); +} + + +InstanceProfileCredentialsProvider::InstanceProfileCredentialsProvider(const std::shared_ptr<Aws::Config::EC2InstanceProfileConfigLoader>& loader, long refreshRateMs) : + m_ec2MetadataConfigLoader(loader), + m_loadFrequencyMs(refreshRateMs) +{ + AWS_LOGSTREAM_INFO(INSTANCE_LOG_TAG, "Creating Instance with injected EC2MetadataClient and refresh rate " << refreshRateMs); +} + + +AWSCredentials InstanceProfileCredentialsProvider::GetAWSCredentials() +{ + RefreshIfExpired(); + ReaderLockGuard guard(m_reloadLock); + auto profileIter = m_ec2MetadataConfigLoader->GetProfiles().find(Aws::Config::INSTANCE_PROFILE_KEY); + + if(profileIter != m_ec2MetadataConfigLoader->GetProfiles().end()) + { + return profileIter->second.GetCredentials(); + } + + return AWSCredentials(); +} + +void InstanceProfileCredentialsProvider::Reload() +{ + AWS_LOGSTREAM_INFO(INSTANCE_LOG_TAG, "Credentials have expired attempting to repull from EC2 Metadata Service."); + m_ec2MetadataConfigLoader->Load(); + AWSCredentialsProvider::Reload(); +} + +void InstanceProfileCredentialsProvider::RefreshIfExpired() +{ + AWS_LOGSTREAM_DEBUG(INSTANCE_LOG_TAG, "Checking if latest credential pull has expired."); + ReaderLockGuard guard(m_reloadLock); + if (!IsTimeToRefresh(m_loadFrequencyMs)) + { + return; + } + + guard.UpgradeToWriterLock(); + if (!IsTimeToRefresh(m_loadFrequencyMs)) // double-checked lock to avoid refreshing twice + { + return; + } + Reload(); +} + +static const char TASK_ROLE_LOG_TAG[] = "TaskRoleCredentialsProvider"; + +TaskRoleCredentialsProvider::TaskRoleCredentialsProvider(const char* URI, long refreshRateMs) : + m_ecsCredentialsClient(Aws::MakeShared<Aws::Internal::ECSCredentialsClient>(TASK_ROLE_LOG_TAG, URI)), + m_loadFrequencyMs(refreshRateMs) +{ + AWS_LOGSTREAM_INFO(TASK_ROLE_LOG_TAG, "Creating TaskRole with default ECSCredentialsClient and refresh rate " << refreshRateMs); +} + +TaskRoleCredentialsProvider::TaskRoleCredentialsProvider(const char* endpoint, const char* token, long refreshRateMs) : + m_ecsCredentialsClient(Aws::MakeShared<Aws::Internal::ECSCredentialsClient>(TASK_ROLE_LOG_TAG, ""/*resourcePath*/, endpoint, token)), + m_loadFrequencyMs(refreshRateMs) +{ + AWS_LOGSTREAM_INFO(TASK_ROLE_LOG_TAG, "Creating TaskRole with default ECSCredentialsClient and refresh rate " << refreshRateMs); +} + +TaskRoleCredentialsProvider::TaskRoleCredentialsProvider( + const std::shared_ptr<Aws::Internal::ECSCredentialsClient>& client, long refreshRateMs) : + m_ecsCredentialsClient(client), + m_loadFrequencyMs(refreshRateMs) +{ + AWS_LOGSTREAM_INFO(TASK_ROLE_LOG_TAG, "Creating TaskRole with default ECSCredentialsClient and refresh rate " << refreshRateMs); +} + +AWSCredentials TaskRoleCredentialsProvider::GetAWSCredentials() +{ + RefreshIfExpired(); + ReaderLockGuard guard(m_reloadLock); + return m_credentials; +} + +bool TaskRoleCredentialsProvider::ExpiresSoon() const +{ + return ((m_credentials.GetExpiration() - Aws::Utils::DateTime::Now()).count() < EXPIRATION_GRACE_PERIOD); +} + +void TaskRoleCredentialsProvider::Reload() +{ + AWS_LOGSTREAM_INFO(TASK_ROLE_LOG_TAG, "Credentials have expired or will expire, attempting to repull from ECS IAM Service."); + + auto credentialsStr = m_ecsCredentialsClient->GetECSCredentials(); + if (credentialsStr.empty()) return; + + Json::JsonValue credentialsDoc(credentialsStr); + if (!credentialsDoc.WasParseSuccessful()) + { + AWS_LOGSTREAM_ERROR(TASK_ROLE_LOG_TAG, "Failed to parse output from ECSCredentialService."); + return; + } + + Aws::String accessKey, secretKey, token; + Utils::Json::JsonView credentialsView(credentialsDoc); + accessKey = credentialsView.GetString("AccessKeyId"); + secretKey = credentialsView.GetString("SecretAccessKey"); + token = credentialsView.GetString("Token"); + AWS_LOGSTREAM_DEBUG(TASK_ROLE_LOG_TAG, "Successfully pulled credentials from metadata service with access key " << accessKey); + + m_credentials.SetAWSAccessKeyId(accessKey); + m_credentials.SetAWSSecretKey(secretKey); + m_credentials.SetSessionToken(token); + m_credentials.SetExpiration(Aws::Utils::DateTime(credentialsView.GetString("Expiration"), DateFormat::ISO_8601)); + AWSCredentialsProvider::Reload(); +} + +void TaskRoleCredentialsProvider::RefreshIfExpired() +{ + AWS_LOGSTREAM_DEBUG(TASK_ROLE_LOG_TAG, "Checking if latest credential pull has expired."); + ReaderLockGuard guard(m_reloadLock); + if (!m_credentials.IsEmpty() && !IsTimeToRefresh(m_loadFrequencyMs) && !ExpiresSoon()) + { + return; + } + + guard.UpgradeToWriterLock(); + + if (!m_credentials.IsEmpty() && !IsTimeToRefresh(m_loadFrequencyMs) && !ExpiresSoon()) + { + return; + } + + Reload(); +} + +static const char PROCESS_LOG_TAG[] = "ProcessCredentialsProvider"; +ProcessCredentialsProvider::ProcessCredentialsProvider() : + m_profileToUse(Aws::Auth::GetConfigProfileName()) +{ + AWS_LOGSTREAM_INFO(PROCESS_LOG_TAG, "Setting process credentials provider to read config from " << m_profileToUse); +} + +ProcessCredentialsProvider::ProcessCredentialsProvider(const Aws::String& profile) : + m_profileToUse(profile) +{ + AWS_LOGSTREAM_INFO(PROCESS_LOG_TAG, "Setting process credentials provider to read config from " << m_profileToUse); +} + +AWSCredentials ProcessCredentialsProvider::GetAWSCredentials() +{ + RefreshIfExpired(); + ReaderLockGuard guard(m_reloadLock); + return m_credentials; +} + + +void ProcessCredentialsProvider::Reload() +{ + auto profile = Aws::Config::GetCachedConfigProfile(m_profileToUse); + const Aws::String &command = profile.GetCredentialProcess(); + if (command.empty()) + { + AWS_LOGSTREAM_ERROR(PROCESS_LOG_TAG, "Failed to find credential process's profile: " << m_profileToUse); + return; + } + m_credentials = GetCredentialsFromProcess(command); +} + +void ProcessCredentialsProvider::RefreshIfExpired() +{ + ReaderLockGuard guard(m_reloadLock); + if (!m_credentials.IsExpiredOrEmpty()) + { + return; + } + + guard.UpgradeToWriterLock(); + if (!m_credentials.IsExpiredOrEmpty()) // double-checked lock to avoid refreshing twice + { + return; + } + + Reload(); +} + +AWSCredentials Aws::Auth::GetCredentialsFromProcess(const Aws::String& process) +{ + Aws::String command = process; + command.append(" 2>&1"); // redirect stderr to stdout + Aws::String result = Aws::Utils::StringUtils::Trim(Aws::OSVersionInfo::GetSysCommandOutput(command.c_str()).c_str()); + Json::JsonValue credentialsDoc(result); + if (!credentialsDoc.WasParseSuccessful()) + { + AWS_LOGSTREAM_ERROR(PROFILE_LOG_TAG, "Failed to load credential from running: " << command << " Error: " << result); + return {}; + } + + Aws::Utils::Json::JsonView credentialsView(credentialsDoc); + if (!credentialsView.KeyExists("Version") || credentialsView.GetInteger("Version") != 1) + { + AWS_LOGSTREAM_ERROR(PROFILE_LOG_TAG, "Encountered an unsupported process credentials payload version:" << credentialsView.GetInteger("Version")); + return {}; + } + + AWSCredentials credentials; + Aws::String accessKey, secretKey, token, expire; + if (credentialsView.KeyExists("AccessKeyId")) + { + credentials.SetAWSAccessKeyId(credentialsView.GetString("AccessKeyId")); + } + + if (credentialsView.KeyExists("SecretAccessKey")) + { + credentials.SetAWSSecretKey(credentialsView.GetString("SecretAccessKey")); + } + + if (credentialsView.KeyExists("SessionToken")) + { + credentials.SetSessionToken(credentialsView.GetString("SessionToken")); + } + + if (credentialsView.KeyExists("Expiration")) + { + const auto expiration = Aws::Utils::DateTime(credentialsView.GetString("Expiration"), DateFormat::ISO_8601); + if (expiration.WasParseSuccessful()) + { + credentials.SetExpiration(expiration); + } + else + { + AWS_LOGSTREAM_ERROR(PROFILE_LOG_TAG, "Failed to parse credential's expiration value as an ISO 8601 Date. Credentials will be marked expired."); + credentials.SetExpiration(Aws::Utils::DateTime::Now()); + } + } + else + { + credentials.SetExpiration((std::chrono::time_point<std::chrono::system_clock>::max)()); + } + + AWS_LOGSTREAM_DEBUG(PROFILE_LOG_TAG, "Successfully pulled credentials from process credential with AccessKey: " << accessKey << ", Expiration:" << credentialsView.GetString("Expiration")); + return credentials; +} + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSCredentialsProviderChain.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSCredentialsProviderChain.cpp new file mode 100644 index 0000000000..373136d96a --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSCredentialsProviderChain.cpp @@ -0,0 +1,77 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/auth/AWSCredentialsProviderChain.h> +#include <aws/core/auth/STSCredentialsProvider.h> +#include <aws/core/platform/Environment.h> +#include <aws/core/utils/memory/AWSMemory.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/logging/LogMacros.h> + +using namespace Aws::Auth; + +static const char AWS_ECS_CONTAINER_CREDENTIALS_RELATIVE_URI[] = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"; +static const char AWS_ECS_CONTAINER_CREDENTIALS_FULL_URI[] = "AWS_CONTAINER_CREDENTIALS_FULL_URI"; +static const char AWS_ECS_CONTAINER_AUTHORIZATION_TOKEN[] = "AWS_CONTAINER_AUTHORIZATION_TOKEN"; +static const char AWS_EC2_METADATA_DISABLED[] = "AWS_EC2_METADATA_DISABLED"; +static const char DefaultCredentialsProviderChainTag[] = "DefaultAWSCredentialsProviderChain"; + +AWSCredentials AWSCredentialsProviderChain::GetAWSCredentials() +{ + for (auto&& credentialsProvider : m_providerChain) + { + AWSCredentials credentials = credentialsProvider->GetAWSCredentials(); + if (!credentials.GetAWSAccessKeyId().empty() && !credentials.GetAWSSecretKey().empty()) + { + return credentials; + } + } + + return AWSCredentials(); +} + +DefaultAWSCredentialsProviderChain::DefaultAWSCredentialsProviderChain() : AWSCredentialsProviderChain() +{ + AddProvider(Aws::MakeShared<EnvironmentAWSCredentialsProvider>(DefaultCredentialsProviderChainTag)); + AddProvider(Aws::MakeShared<ProfileConfigFileAWSCredentialsProvider>(DefaultCredentialsProviderChainTag)); + AddProvider(Aws::MakeShared<ProcessCredentialsProvider>(DefaultCredentialsProviderChainTag)); + AddProvider(Aws::MakeShared<STSAssumeRoleWebIdentityCredentialsProvider>(DefaultCredentialsProviderChainTag)); + + //ECS TaskRole Credentials only available when ENVIRONMENT VARIABLE is set + const auto relativeUri = Aws::Environment::GetEnv(AWS_ECS_CONTAINER_CREDENTIALS_RELATIVE_URI); + AWS_LOGSTREAM_DEBUG(DefaultCredentialsProviderChainTag, "The environment variable value " << AWS_ECS_CONTAINER_CREDENTIALS_RELATIVE_URI + << " is " << relativeUri); + + const auto absoluteUri = Aws::Environment::GetEnv(AWS_ECS_CONTAINER_CREDENTIALS_FULL_URI); + AWS_LOGSTREAM_DEBUG(DefaultCredentialsProviderChainTag, "The environment variable value " << AWS_ECS_CONTAINER_CREDENTIALS_FULL_URI + << " is " << absoluteUri); + + const auto ec2MetadataDisabled = Aws::Environment::GetEnv(AWS_EC2_METADATA_DISABLED); + AWS_LOGSTREAM_DEBUG(DefaultCredentialsProviderChainTag, "The environment variable value " << AWS_EC2_METADATA_DISABLED + << " is " << ec2MetadataDisabled); + + if (!relativeUri.empty()) + { + AddProvider(Aws::MakeShared<TaskRoleCredentialsProvider>(DefaultCredentialsProviderChainTag, relativeUri.c_str())); + AWS_LOGSTREAM_INFO(DefaultCredentialsProviderChainTag, "Added ECS metadata service credentials provider with relative path: [" + << relativeUri << "] to the provider chain."); + } + else if (!absoluteUri.empty()) + { + const auto token = Aws::Environment::GetEnv(AWS_ECS_CONTAINER_AUTHORIZATION_TOKEN); + AddProvider(Aws::MakeShared<TaskRoleCredentialsProvider>(DefaultCredentialsProviderChainTag, + absoluteUri.c_str(), token.c_str())); + + //DO NOT log the value of the authorization token for security purposes. + AWS_LOGSTREAM_INFO(DefaultCredentialsProviderChainTag, "Added ECS credentials provider with URI: [" + << absoluteUri << "] to the provider chain with a" << (token.empty() ? "n empty " : " non-empty ") + << "authorization token."); + } + else if (Aws::Utils::StringUtils::ToLower(ec2MetadataDisabled.c_str()) != "true") + { + AddProvider(Aws::MakeShared<InstanceProfileCredentialsProvider>(DefaultCredentialsProviderChainTag)); + AWS_LOGSTREAM_INFO(DefaultCredentialsProviderChainTag, "Added EC2 metadata service credentials provider to the provider chain."); + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/STSCredentialsProvider.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/STSCredentialsProvider.cpp new file mode 100644 index 0000000000..3f48c9e0c7 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/STSCredentialsProvider.cpp @@ -0,0 +1,163 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#include <aws/core/auth/STSCredentialsProvider.h> +#include <aws/core/config/AWSProfileConfigLoader.h> +#include <aws/core/platform/Environment.h> +#include <aws/core/platform/FileSystem.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/FileSystemUtils.h> +#include <aws/core/client/SpecifiedRetryableErrorsRetryStrategy.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/UUID.h> +#include <cstdlib> +#include <fstream> +#include <string.h> +#include <climits> + + +using namespace Aws::Utils; +using namespace Aws::Utils::Logging; +using namespace Aws::Auth; +using namespace Aws::Internal; +using namespace Aws::FileSystem; +using namespace Aws::Client; +using Aws::Utils::Threading::ReaderLockGuard; +using Aws::Utils::Threading::WriterLockGuard; + +static const char STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG[] = "STSAssumeRoleWithWebIdentityCredentialsProvider"; +STSAssumeRoleWebIdentityCredentialsProvider::STSAssumeRoleWebIdentityCredentialsProvider() : + m_initialized(false) +{ + // check environment variables + Aws::String tmpRegion = Aws::Environment::GetEnv("AWS_DEFAULT_REGION"); + m_roleArn = Aws::Environment::GetEnv("AWS_ROLE_ARN"); + m_tokenFile = Aws::Environment::GetEnv("AWS_WEB_IDENTITY_TOKEN_FILE"); + m_sessionName = Aws::Environment::GetEnv("AWS_ROLE_SESSION_NAME"); + + // check profile_config if either m_roleArn or m_tokenFile is not loaded from environment variable + // region source is not enforced, but we need it to construct sts endpoint, if we can't find from environment, we should check if it's set in config file. + if (m_roleArn.empty() || m_tokenFile.empty() || tmpRegion.empty()) + { + auto profile = Aws::Config::GetCachedConfigProfile(Aws::Auth::GetConfigProfileName()); + if (tmpRegion.empty()) + { + tmpRegion = profile.GetRegion(); + } + // If either of these two were not found from environment, use whatever found for all three in config file + if (m_roleArn.empty() || m_tokenFile.empty()) + { + m_roleArn = profile.GetRoleArn(); + m_tokenFile = profile.GetValue("web_identity_token_file"); + m_sessionName = profile.GetValue("role_session_name"); + } + } + + if (m_tokenFile.empty()) + { + AWS_LOGSTREAM_WARN(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Token file must be specified to use STS AssumeRole web identity creds provider."); + return; // No need to do further constructing + } + else + { + AWS_LOGSTREAM_DEBUG(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Resolved token_file from profile_config or environment variable to be " << m_tokenFile); + } + + if (m_roleArn.empty()) + { + AWS_LOGSTREAM_WARN(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "RoleArn must be specified to use STS AssumeRole web identity creds provider."); + return; // No need to do further constructing + } + else + { + AWS_LOGSTREAM_DEBUG(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Resolved role_arn from profile_config or environment variable to be " << m_roleArn); + } + + if (tmpRegion.empty()) + { + tmpRegion = Aws::Region::US_EAST_1; + } + else + { + AWS_LOGSTREAM_DEBUG(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Resolved region from profile_config or environment variable to be " << tmpRegion); + } + + if (m_sessionName.empty()) + { + m_sessionName = Aws::Utils::UUID::RandomUUID(); + } + else + { + AWS_LOGSTREAM_DEBUG(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Resolved session_name from profile_config or environment variable to be " << m_sessionName); + } + + Aws::Client::ClientConfiguration config; + config.scheme = Aws::Http::Scheme::HTTPS; + config.region = tmpRegion; + + Aws::Vector<Aws::String> retryableErrors; + retryableErrors.push_back("IDPCommunicationError"); + retryableErrors.push_back("InvalidIdentityToken"); + + config.retryStrategy = Aws::MakeShared<SpecifiedRetryableErrorsRetryStrategy>(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, retryableErrors, 3/*maxRetries*/); + + m_client = Aws::MakeUnique<Aws::Internal::STSCredentialsClient>(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, config); + m_initialized = true; + AWS_LOGSTREAM_INFO(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Creating STS AssumeRole with web identity creds provider."); +} + +AWSCredentials STSAssumeRoleWebIdentityCredentialsProvider::GetAWSCredentials() +{ + // A valid client means required information like role arn and token file were constructed correctly. + // We can use this provider to load creds, otherwise, we can just return empty creds. + if (!m_initialized) + { + return Aws::Auth::AWSCredentials(); + } + RefreshIfExpired(); + ReaderLockGuard guard(m_reloadLock); + return m_credentials; +} + +void STSAssumeRoleWebIdentityCredentialsProvider::Reload() +{ + AWS_LOGSTREAM_INFO(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Credentials have expired, attempting to renew from STS."); + + Aws::IFStream tokenFile(m_tokenFile.c_str()); + if(tokenFile) + { + Aws::String token((std::istreambuf_iterator<char>(tokenFile)), std::istreambuf_iterator<char>()); + m_token = token; + } + else + { + AWS_LOGSTREAM_ERROR(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Can't open token file: " << m_tokenFile); + return; + } + STSCredentialsClient::STSAssumeRoleWithWebIdentityRequest request {m_sessionName, m_roleArn, m_token}; + + auto result = m_client->GetAssumeRoleWithWebIdentityCredentials(request); + AWS_LOGSTREAM_TRACE(STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG, "Successfully retrieved credentials with AWS_ACCESS_KEY: " << result.creds.GetAWSAccessKeyId()); + m_credentials = result.creds; +} + +void STSAssumeRoleWebIdentityCredentialsProvider::RefreshIfExpired() +{ + ReaderLockGuard guard(m_reloadLock); + if (!m_credentials.IsExpiredOrEmpty()) + { + return; + } + + guard.UpgradeToWriterLock(); + if (!m_credentials.IsExpiredOrEmpty()) // double-checked lock to avoid refreshing twice + { + return; + } + + Reload(); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSClient.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSClient.cpp new file mode 100644 index 0000000000..e1ff064840 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSClient.cpp @@ -0,0 +1,1098 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/client/AWSClient.h> +#include <aws/core/AmazonWebServiceRequest.h> +#include <aws/core/auth/AWSAuthSigner.h> +#include <aws/core/auth/AWSAuthSignerProvider.h> +#include <aws/core/client/AWSError.h> +#include <aws/core/client/AWSErrorMarshaller.h> +#include <aws/core/client/ClientConfiguration.h> +#include <aws/core/client/CoreErrors.h> +#include <aws/core/client/RetryStrategy.h> +#include <aws/core/http/HttpClient.h> +#include <aws/core/http/HttpClientFactory.h> +#include <aws/core/http/HttpResponse.h> +#include <aws/core/http/standard/StandardHttpResponse.h> +#include <aws/core/http/URI.h> +#include <aws/core/utils/stream/ResponseStream.h> +#include <aws/core/utils/json/JsonSerializer.h> +#include <aws/core/utils/Outcome.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/xml/XmlSerializer.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/Globals.h> +#include <aws/core/utils/EnumParseOverflowContainer.h> +#include <aws/core/utils/crypto/MD5.h> +#include <aws/core/utils/HashingUtils.h> +#include <aws/core/utils/crypto/Factories.h> +#include <aws/core/utils/event/EventStream.h> +#include <aws/core/utils/UUID.h> +#include <aws/core/monitoring/MonitoringManager.h> +#include <aws/core/Region.h> +#include <aws/core/utils/DNS.h> +#include <aws/core/Version.h> +#include <aws/core/platform/OSVersionInfo.h> + +#include <cstring> +#include <cassert> + +using namespace Aws; +using namespace Aws::Client; +using namespace Aws::Http; +using namespace Aws::Utils; +using namespace Aws::Utils::Json; +using namespace Aws::Utils::Xml; + +static const int SUCCESS_RESPONSE_MIN = 200; +static const int SUCCESS_RESPONSE_MAX = 299; + +static const char AWS_CLIENT_LOG_TAG[] = "AWSClient"; +//4 Minutes +static const std::chrono::milliseconds TIME_DIFF_MAX = std::chrono::minutes(4); +//-4 Minutes +static const std::chrono::milliseconds TIME_DIFF_MIN = std::chrono::minutes(-4); + +static CoreErrors GuessBodylessErrorType(Aws::Http::HttpResponseCode responseCode) +{ + switch (responseCode) + { + case HttpResponseCode::FORBIDDEN: + case HttpResponseCode::UNAUTHORIZED: + return CoreErrors::ACCESS_DENIED; + case HttpResponseCode::NOT_FOUND: + return CoreErrors::RESOURCE_NOT_FOUND; + default: + return CoreErrors::UNKNOWN; + } +} + +struct RequestInfo +{ + Aws::Utils::DateTime ttl; + long attempt; + long maxAttempts; + + operator String() + { + Aws::StringStream ss; + if (ttl.WasParseSuccessful() && ttl != DateTime()) + { + assert(attempt > 1); + ss << "ttl=" << ttl.ToGmtString(DateFormat::ISO_8601_BASIC) << "; "; + } + ss << "attempt=" << attempt; + if (maxAttempts > 0) + { + ss << "; max=" << maxAttempts; + } + return ss.str(); + } +}; + +AWSClient::AWSClient(const Aws::Client::ClientConfiguration& configuration, + const std::shared_ptr<Aws::Client::AWSAuthSigner>& signer, + const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller) : + m_region(configuration.region), + m_httpClient(CreateHttpClient(configuration)), + m_signerProvider(Aws::MakeUnique<Aws::Auth::DefaultAuthSignerProvider>(AWS_CLIENT_LOG_TAG, signer)), + m_errorMarshaller(errorMarshaller), + m_retryStrategy(configuration.retryStrategy), + m_writeRateLimiter(configuration.writeRateLimiter), + m_readRateLimiter(configuration.readRateLimiter), + m_userAgent(configuration.userAgent), + m_customizedUserAgent(!m_userAgent.empty()), + m_hash(Aws::Utils::Crypto::CreateMD5Implementation()), + m_requestTimeoutMs(configuration.requestTimeoutMs), + m_enableClockSkewAdjustment(configuration.enableClockSkewAdjustment) +{ + SetServiceClientName("AWSBaseClient"); +} + +AWSClient::AWSClient(const Aws::Client::ClientConfiguration& configuration, + const std::shared_ptr<Aws::Auth::AWSAuthSignerProvider>& signerProvider, + const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller) : + m_region(configuration.region), + m_httpClient(CreateHttpClient(configuration)), + m_signerProvider(signerProvider), + m_errorMarshaller(errorMarshaller), + m_retryStrategy(configuration.retryStrategy), + m_writeRateLimiter(configuration.writeRateLimiter), + m_readRateLimiter(configuration.readRateLimiter), + m_userAgent(configuration.userAgent), + m_customizedUserAgent(!m_userAgent.empty()), + m_hash(Aws::Utils::Crypto::CreateMD5Implementation()), + m_requestTimeoutMs(configuration.requestTimeoutMs), + m_enableClockSkewAdjustment(configuration.enableClockSkewAdjustment) +{ + SetServiceClientName("AWSBaseClient"); +} + +void AWSClient::SetServiceClientName(const Aws::String& name) +{ + m_serviceName = name; + if (!m_customizedUserAgent) + { + Aws::StringStream ss; + ss << "aws-sdk-cpp/" << Version::GetVersionString() << "/" << m_serviceName << "/" << Aws::OSVersionInfo::ComputeOSVersionString() + << " " << Version::GetCompilerVersionString(); + m_userAgent = ss.str(); + } +} + +void AWSClient::DisableRequestProcessing() +{ + m_httpClient->DisableRequestProcessing(); +} + +void AWSClient::EnableRequestProcessing() +{ + m_httpClient->EnableRequestProcessing(); +} + +Aws::Client::AWSAuthSigner* AWSClient::GetSignerByName(const char* name) const +{ + const auto& signer = m_signerProvider->GetSigner(name); + return signer ? signer.get() : nullptr; +} + +static DateTime GetServerTimeFromError(const AWSError<CoreErrors> error) +{ + const Http::HeaderValueCollection& headers = error.GetResponseHeaders(); + auto awsDateHeaderIter = headers.find(StringUtils::ToLower(Http::AWS_DATE_HEADER)); + auto dateHeaderIter = headers.find(StringUtils::ToLower(Http::DATE_HEADER)); + if (awsDateHeaderIter != headers.end()) + { + return DateTime(awsDateHeaderIter->second.c_str(), DateFormat::AutoDetect); + } + else if (dateHeaderIter != headers.end()) + { + return DateTime(dateHeaderIter->second.c_str(), DateFormat::AutoDetect); + } + else + { + return DateTime(); + } +} + +bool AWSClient::AdjustClockSkew(HttpResponseOutcome& outcome, const char* signerName) const +{ + if (m_enableClockSkewAdjustment) + { + auto signer = GetSignerByName(signerName); + //detect clock skew and try to correct. + AWS_LOGSTREAM_WARN(AWS_CLIENT_LOG_TAG, "If the signature check failed. This could be because of a time skew. Attempting to adjust the signer."); + + DateTime serverTime = GetServerTimeFromError(outcome.GetError()); + const auto signingTimestamp = signer->GetSigningTimestamp(); + if (!serverTime.WasParseSuccessful() || serverTime == DateTime()) + { + AWS_LOGSTREAM_DEBUG(AWS_CLIENT_LOG_TAG, "Date header was not found in the response, can't attempt to detect clock skew"); + return false; + } + + AWS_LOGSTREAM_DEBUG(AWS_CLIENT_LOG_TAG, "Server time is " << serverTime.ToGmtString(DateFormat::RFC822) << ", while client time is " << DateTime::Now().ToGmtString(DateFormat::RFC822)); + auto diff = DateTime::Diff(serverTime, signingTimestamp); + //only try again if clock skew was the cause of the error. + if (diff >= TIME_DIFF_MAX || diff <= TIME_DIFF_MIN) + { + diff = DateTime::Diff(serverTime, DateTime::Now()); + AWS_LOGSTREAM_INFO(AWS_CLIENT_LOG_TAG, "Computed time difference as " << diff.count() << " milliseconds. Adjusting signer with the skew."); + signer->SetClockSkew(diff); + AWSError<CoreErrors> newError( + outcome.GetError().GetErrorType(), outcome.GetError().GetExceptionName(), outcome.GetError().GetMessage(), true); + newError.SetResponseHeaders(outcome.GetError().GetResponseHeaders()); + newError.SetResponseCode(outcome.GetError().GetResponseCode()); + outcome = std::move(newError); + return true; + } + } + return false; +} + +HttpResponseOutcome AWSClient::AttemptExhaustively(const Aws::Http::URI& uri, + const Aws::AmazonWebServiceRequest& request, + HttpMethod method, + const char* signerName, + const char* signerRegionOverride, + const char* signerServiceNameOverride) const +{ + if (!Aws::Utils::IsValidHost(uri.GetAuthority())) + { + return HttpResponseOutcome(AWSError<CoreErrors>(CoreErrors::VALIDATION, "", "Invalid DNS Label found in URI host", false/*retryable*/)); + } + std::shared_ptr<HttpRequest> httpRequest(CreateHttpRequest(uri, method, request.GetResponseStreamFactory())); + HttpResponseOutcome outcome; + AWSError<CoreErrors> lastError; + Aws::Monitoring::CoreMetricsCollection coreMetrics; + auto contexts = Aws::Monitoring::OnRequestStarted(this->GetServiceClientName(), request.GetServiceRequestName(), httpRequest); + const char* signerRegion = signerRegionOverride; + Aws::String regionFromResponse; + + Aws::String invocationId = UUID::RandomUUID(); + RequestInfo requestInfo; + requestInfo.attempt = 1; + requestInfo.maxAttempts = 0; + httpRequest->SetHeaderValue(Http::SDK_INVOCATION_ID_HEADER, invocationId); + httpRequest->SetHeaderValue(Http::SDK_REQUEST_HEADER, requestInfo); + + for (long retries = 0;; retries++) + { + m_retryStrategy->GetSendToken(); + httpRequest->SetEventStreamRequest(request.IsEventStreamRequest()); + + outcome = AttemptOneRequest(httpRequest, request, signerName, signerRegion, signerServiceNameOverride); + if (retries == 0) + { + m_retryStrategy->RequestBookkeeping(outcome); + } + else + { + m_retryStrategy->RequestBookkeeping(outcome, lastError); + } + coreMetrics.httpClientMetrics = httpRequest->GetRequestMetrics(); + if (outcome.IsSuccess()) + { + Aws::Monitoring::OnRequestSucceeded(this->GetServiceClientName(), request.GetServiceRequestName(), httpRequest, outcome, coreMetrics, contexts); + AWS_LOGSTREAM_TRACE(AWS_CLIENT_LOG_TAG, "Request successful returning."); + break; + } + lastError = outcome.GetError(); + + DateTime serverTime = GetServerTimeFromError(outcome.GetError()); + auto clockSkew = DateTime::Diff(serverTime, DateTime::Now()); + + Aws::Monitoring::OnRequestFailed(this->GetServiceClientName(), request.GetServiceRequestName(), httpRequest, outcome, coreMetrics, contexts); + + if (!m_httpClient->IsRequestProcessingEnabled()) + { + AWS_LOGSTREAM_TRACE(AWS_CLIENT_LOG_TAG, "Request was cancelled externally."); + break; + } + + // Adjust region + bool retryWithCorrectRegion = false; + HttpResponseCode httpResponseCode = outcome.GetError().GetResponseCode(); + if (httpResponseCode == HttpResponseCode::MOVED_PERMANENTLY || // 301 + httpResponseCode == HttpResponseCode::TEMPORARY_REDIRECT || // 307 + httpResponseCode == HttpResponseCode::BAD_REQUEST || // 400 + httpResponseCode == HttpResponseCode::FORBIDDEN) // 403 + { + regionFromResponse = GetErrorMarshaller()->ExtractRegion(outcome.GetError()); + if (m_region == Aws::Region::AWS_GLOBAL && !regionFromResponse.empty() && regionFromResponse != signerRegion) + { + signerRegion = regionFromResponse.c_str(); + retryWithCorrectRegion = true; + } + } + + long sleepMillis = m_retryStrategy->CalculateDelayBeforeNextRetry(outcome.GetError(), retries); + //AdjustClockSkew returns true means clock skew was the problem and skew was adjusted, false otherwise. + //sleep if clock skew and region was NOT the problem. AdjustClockSkew may update error inside outcome. + bool shouldSleep = !AdjustClockSkew(outcome, signerName) && !retryWithCorrectRegion; + + if (!retryWithCorrectRegion && !m_retryStrategy->ShouldRetry(outcome.GetError(), retries)) + { + break; + } + + AWS_LOGSTREAM_WARN(AWS_CLIENT_LOG_TAG, "Request failed, now waiting " << sleepMillis << " ms before attempting again."); + if(request.GetBody()) + { + request.GetBody()->clear(); + request.GetBody()->seekg(0); + } + + if (request.GetRequestRetryHandler()) + { + request.GetRequestRetryHandler()(request); + } + + if (shouldSleep) + { + m_httpClient->RetryRequestSleep(std::chrono::milliseconds(sleepMillis)); + } + + Aws::Http::URI newUri = uri; + Aws::String newEndpoint = GetErrorMarshaller()->ExtractEndpoint(outcome.GetError()); + if (!newEndpoint.empty()) + { + newUri.SetAuthority(newEndpoint); + } + httpRequest = CreateHttpRequest(newUri, method, request.GetResponseStreamFactory()); + + httpRequest->SetHeaderValue(Http::SDK_INVOCATION_ID_HEADER, invocationId); + if (serverTime.WasParseSuccessful() && serverTime != DateTime()) + { + requestInfo.ttl = DateTime::Now() + clockSkew + std::chrono::milliseconds(m_requestTimeoutMs); + } + requestInfo.attempt ++; + requestInfo.maxAttempts = m_retryStrategy->GetMaxAttempts(); + httpRequest->SetHeaderValue(Http::SDK_REQUEST_HEADER, requestInfo); + Aws::Monitoring::OnRequestRetry(this->GetServiceClientName(), request.GetServiceRequestName(), httpRequest, contexts); + } + Aws::Monitoring::OnFinish(this->GetServiceClientName(), request.GetServiceRequestName(), httpRequest, contexts); + return outcome; +} + +HttpResponseOutcome AWSClient::AttemptExhaustively(const Aws::Http::URI& uri, + HttpMethod method, + const char* signerName, + const char* requestName, + const char* signerRegionOverride, + const char* signerServiceNameOverride) const +{ + if (!Aws::Utils::IsValidHost(uri.GetAuthority())) + { + return HttpResponseOutcome(AWSError<CoreErrors>(CoreErrors::VALIDATION, "", "Invalid DNS Label found in URI host", false/*retryable*/)); + } + + std::shared_ptr<HttpRequest> httpRequest(CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod)); + HttpResponseOutcome outcome; + AWSError<CoreErrors> lastError; + Aws::Monitoring::CoreMetricsCollection coreMetrics; + auto contexts = Aws::Monitoring::OnRequestStarted(this->GetServiceClientName(), requestName, httpRequest); + const char* signerRegion = signerRegionOverride; + Aws::String regionFromResponse; + + Aws::String invocationId = UUID::RandomUUID(); + RequestInfo requestInfo; + requestInfo.attempt = 1; + requestInfo.maxAttempts = 0; + httpRequest->SetHeaderValue(Http::SDK_INVOCATION_ID_HEADER, invocationId); + httpRequest->SetHeaderValue(Http::SDK_REQUEST_HEADER, requestInfo); + + for (long retries = 0;; retries++) + { + m_retryStrategy->GetSendToken(); + outcome = AttemptOneRequest(httpRequest, signerName, requestName, signerRegion, signerServiceNameOverride); + if (retries == 0) + { + m_retryStrategy->RequestBookkeeping(outcome); + } + else + { + m_retryStrategy->RequestBookkeeping(outcome, lastError); + } + coreMetrics.httpClientMetrics = httpRequest->GetRequestMetrics(); + if (outcome.IsSuccess()) + { + Aws::Monitoring::OnRequestSucceeded(this->GetServiceClientName(), requestName, httpRequest, outcome, coreMetrics, contexts); + AWS_LOGSTREAM_TRACE(AWS_CLIENT_LOG_TAG, "Request successful returning."); + break; + } + lastError = outcome.GetError(); + + DateTime serverTime = GetServerTimeFromError(outcome.GetError()); + auto clockSkew = DateTime::Diff(serverTime, DateTime::Now()); + + Aws::Monitoring::OnRequestFailed(this->GetServiceClientName(), requestName, httpRequest, outcome, coreMetrics, contexts); + + if (!m_httpClient->IsRequestProcessingEnabled()) + { + AWS_LOGSTREAM_TRACE(AWS_CLIENT_LOG_TAG, "Request was cancelled externally."); + break; + } + + // Adjust region + bool retryWithCorrectRegion = false; + HttpResponseCode httpResponseCode = outcome.GetError().GetResponseCode(); + if (httpResponseCode == HttpResponseCode::MOVED_PERMANENTLY || // 301 + httpResponseCode == HttpResponseCode::TEMPORARY_REDIRECT || // 307 + httpResponseCode == HttpResponseCode::BAD_REQUEST || // 400 + httpResponseCode == HttpResponseCode::FORBIDDEN) // 403 + { + regionFromResponse = GetErrorMarshaller()->ExtractRegion(outcome.GetError()); + if (m_region == Aws::Region::AWS_GLOBAL && !regionFromResponse.empty() && regionFromResponse != signerRegion) + { + signerRegion = regionFromResponse.c_str(); + retryWithCorrectRegion = true; + } + } + + long sleepMillis = m_retryStrategy->CalculateDelayBeforeNextRetry(outcome.GetError(), retries); + //AdjustClockSkew returns true means clock skew was the problem and skew was adjusted, false otherwise. + //sleep if clock skew and region was NOT the problem. AdjustClockSkew may update error inside outcome. + bool shouldSleep = !AdjustClockSkew(outcome, signerName) && !retryWithCorrectRegion; + + if (!retryWithCorrectRegion && !m_retryStrategy->ShouldRetry(outcome.GetError(), retries)) + { + break; + } + + AWS_LOGSTREAM_WARN(AWS_CLIENT_LOG_TAG, "Request failed, now waiting " << sleepMillis << " ms before attempting again."); + + if (shouldSleep) + { + m_httpClient->RetryRequestSleep(std::chrono::milliseconds(sleepMillis)); + } + + Aws::Http::URI newUri = uri; + Aws::String newEndpoint = GetErrorMarshaller()->ExtractEndpoint(outcome.GetError()); + if (!newEndpoint.empty()) + { + newUri.SetAuthority(newEndpoint); + } + httpRequest = CreateHttpRequest(newUri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + + httpRequest->SetHeaderValue(Http::SDK_INVOCATION_ID_HEADER, invocationId); + if (serverTime.WasParseSuccessful() && serverTime != DateTime()) + { + requestInfo.ttl = DateTime::Now() + clockSkew + std::chrono::milliseconds(m_requestTimeoutMs); + } + requestInfo.attempt ++; + requestInfo.maxAttempts = m_retryStrategy->GetMaxAttempts(); + httpRequest->SetHeaderValue(Http::SDK_REQUEST_HEADER, requestInfo); + Aws::Monitoring::OnRequestRetry(this->GetServiceClientName(), requestName, httpRequest, contexts); + } + Aws::Monitoring::OnFinish(this->GetServiceClientName(), requestName, httpRequest, contexts); + return outcome; +} + +static bool DoesResponseGenerateError(const std::shared_ptr<HttpResponse>& response) +{ + if (response->HasClientError()) return true; + + int responseCode = static_cast<int>(response->GetResponseCode()); + return responseCode < SUCCESS_RESPONSE_MIN || responseCode > SUCCESS_RESPONSE_MAX; + +} + +HttpResponseOutcome AWSClient::AttemptOneRequest(const std::shared_ptr<HttpRequest>& httpRequest, const Aws::AmazonWebServiceRequest& request, + const char* signerName, const char* signerRegionOverride, const char* signerServiceNameOverride) const +{ + BuildHttpRequest(request, httpRequest); + auto signer = GetSignerByName(signerName); + if (!signer->SignRequest(*httpRequest, signerRegionOverride, signerServiceNameOverride, request.SignBody())) + { + AWS_LOGSTREAM_ERROR(AWS_CLIENT_LOG_TAG, "Request signing failed. Returning error."); + return HttpResponseOutcome(AWSError<CoreErrors>(CoreErrors::CLIENT_SIGNING_FAILURE, "", "SDK failed to sign the request", false/*retryable*/)); + } + + if (request.GetRequestSignedHandler()) + { + request.GetRequestSignedHandler()(*httpRequest); + } + + AWS_LOGSTREAM_DEBUG(AWS_CLIENT_LOG_TAG, "Request Successfully signed"); + std::shared_ptr<HttpResponse> httpResponse( + m_httpClient->MakeRequest(httpRequest, m_readRateLimiter.get(), m_writeRateLimiter.get())); + + if (DoesResponseGenerateError(httpResponse)) + { + AWS_LOGSTREAM_DEBUG(AWS_CLIENT_LOG_TAG, "Request returned error. Attempting to generate appropriate error codes from response"); + auto error = BuildAWSError(httpResponse); + return HttpResponseOutcome(std::move(error)); + } + + AWS_LOGSTREAM_DEBUG(AWS_CLIENT_LOG_TAG, "Request returned successful response."); + + return HttpResponseOutcome(std::move(httpResponse)); +} + +HttpResponseOutcome AWSClient::AttemptOneRequest(const std::shared_ptr<HttpRequest>& httpRequest, + const char* signerName, const char* requestName, const char* signerRegionOverride, const char* signerServiceNameOverride) const +{ + AWS_UNREFERENCED_PARAM(requestName); + + auto signer = GetSignerByName(signerName); + if (!signer->SignRequest(*httpRequest, signerRegionOverride, signerServiceNameOverride, true)) + { + AWS_LOGSTREAM_ERROR(AWS_CLIENT_LOG_TAG, "Request signing failed. Returning error."); + return HttpResponseOutcome(AWSError<CoreErrors>(CoreErrors::CLIENT_SIGNING_FAILURE, "", "SDK failed to sign the request", false/*retryable*/)); + } + + //user agent and headers like that shouldn't be signed for the sake of compatibility with proxies which MAY mutate that header. + AddCommonHeaders(*httpRequest); + + AWS_LOGSTREAM_DEBUG(AWS_CLIENT_LOG_TAG, "Request Successfully signed"); + std::shared_ptr<HttpResponse> httpResponse( + m_httpClient->MakeRequest(httpRequest, m_readRateLimiter.get(), m_writeRateLimiter.get())); + + if (DoesResponseGenerateError(httpResponse)) + { + AWS_LOGSTREAM_DEBUG(AWS_CLIENT_LOG_TAG, "Request returned error. Attempting to generate appropriate error codes from response"); + auto error = BuildAWSError(httpResponse); + return HttpResponseOutcome(std::move(error)); + } + + AWS_LOGSTREAM_DEBUG(AWS_CLIENT_LOG_TAG, "Request returned successful response."); + + return HttpResponseOutcome(std::move(httpResponse)); +} + +StreamOutcome AWSClient::MakeRequestWithUnparsedResponse(const Aws::Http::URI& uri, + const Aws::AmazonWebServiceRequest& request, + Http::HttpMethod method, + const char* signerName, + const char* signerRegionOverride, + const char* signerServiceNameOverride) const +{ + HttpResponseOutcome httpResponseOutcome = AttemptExhaustively(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride); + if (httpResponseOutcome.IsSuccess()) + { + return StreamOutcome(AmazonWebServiceResult<Stream::ResponseStream>( + httpResponseOutcome.GetResult()->SwapResponseStreamOwnership(), + httpResponseOutcome.GetResult()->GetHeaders(), httpResponseOutcome.GetResult()->GetResponseCode())); + } + + return StreamOutcome(std::move(httpResponseOutcome)); +} + +StreamOutcome AWSClient::MakeRequestWithUnparsedResponse(const Aws::Http::URI& uri, + Http::HttpMethod method, + const char* signerName, + const char* requestName, + const char* signerRegionOverride, + const char* signerServiceNameOverride) const +{ + HttpResponseOutcome httpResponseOutcome = AttemptExhaustively(uri, method, signerName, requestName, signerRegionOverride, signerServiceNameOverride); + if (httpResponseOutcome.IsSuccess()) + { + return StreamOutcome(AmazonWebServiceResult<Stream::ResponseStream>( + httpResponseOutcome.GetResult()->SwapResponseStreamOwnership(), + httpResponseOutcome.GetResult()->GetHeaders(), httpResponseOutcome.GetResult()->GetResponseCode())); + } + + return StreamOutcome(std::move(httpResponseOutcome)); +} + +XmlOutcome AWSXMLClient::MakeRequestWithEventStream(const Aws::Http::URI& uri, + const Aws::AmazonWebServiceRequest& request, + Http::HttpMethod method, + const char* signerName, + const char* signerRegionOverride, + const char* signerServiceNameOverride) const +{ + HttpResponseOutcome httpOutcome = AttemptExhaustively(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride); + if (httpOutcome.IsSuccess()) + { + return XmlOutcome(AmazonWebServiceResult<XmlDocument>(XmlDocument(), httpOutcome.GetResult()->GetHeaders())); + } + + return XmlOutcome(std::move(httpOutcome)); +} + +XmlOutcome AWSXMLClient::MakeRequestWithEventStream(const Aws::Http::URI& uri, + Http::HttpMethod method, + const char* signerName, + const char* requestName, + const char* signerRegionOverride, + const char* signerServiceNameOverride) const +{ + HttpResponseOutcome httpOutcome = AttemptExhaustively(uri, method, signerName, requestName, signerRegionOverride, signerServiceNameOverride); + if (httpOutcome.IsSuccess()) + { + return XmlOutcome(AmazonWebServiceResult<XmlDocument>(XmlDocument(), httpOutcome.GetResult()->GetHeaders())); + } + + return XmlOutcome(std::move(httpOutcome)); +} + +void AWSClient::AddHeadersToRequest(const std::shared_ptr<Aws::Http::HttpRequest>& httpRequest, + const Http::HeaderValueCollection& headerValues) const +{ + for (auto const& headerValue : headerValues) + { + httpRequest->SetHeaderValue(headerValue.first, headerValue.second); + } + + AddCommonHeaders(*httpRequest); +} + +void AWSClient::AddContentBodyToRequest(const std::shared_ptr<Aws::Http::HttpRequest>& httpRequest, + const std::shared_ptr<Aws::IOStream>& body, bool needsContentMd5, bool isChunked) const +{ + httpRequest->AddContentBody(body); + + //If there is no body, we have a content length of 0 + //note: we also used to remove content-type, but S3 actually needs content-type on InitiateMultipartUpload and it isn't + //forbiden by the spec. If we start getting weird errors related to this, make sure it isn't caused by this removal. + if (!body) + { + AWS_LOGSTREAM_TRACE(AWS_CLIENT_LOG_TAG, "No content body, content-length headers"); + + if(httpRequest->GetMethod() == HttpMethod::HTTP_POST || httpRequest->GetMethod() == HttpMethod::HTTP_PUT) + { + httpRequest->SetHeaderValue(Http::CONTENT_LENGTH_HEADER, "0"); + } + else + { + httpRequest->DeleteHeader(Http::CONTENT_LENGTH_HEADER); + } + } + + //Add transfer-encoding:chunked to header + if (body && isChunked) + { + httpRequest->SetTransferEncoding(CHUNKED_VALUE); + } + //in the scenario where we are adding a content body as a stream, the request object likely already + //has a content-length header set and we don't want to seek the stream just to find this information. + else if (body && !httpRequest->HasHeader(Http::CONTENT_LENGTH_HEADER)) + { + if (!m_httpClient->SupportsChunkedTransferEncoding()) + { + AWS_LOGSTREAM_WARN(AWS_CLIENT_LOG_TAG, "This http client doesn't support transfer-encoding:chunked. " << + "The request may fail if it's not a seekable stream."); + } + AWS_LOGSTREAM_TRACE(AWS_CLIENT_LOG_TAG, "Found body, but content-length has not been set, attempting to compute content-length"); + body->seekg(0, body->end); + auto streamSize = body->tellg(); + body->seekg(0, body->beg); + Aws::StringStream ss; + ss << streamSize; + httpRequest->SetContentLength(ss.str()); + } + + if (needsContentMd5 && body && !httpRequest->HasHeader(Http::CONTENT_MD5_HEADER)) + { + AWS_LOGSTREAM_TRACE(AWS_CLIENT_LOG_TAG, "Found body, and content-md5 needs to be set" << + ", attempting to compute content-md5"); + + //changing the internal state of the hash computation is not a logical state + //change as far as constness goes for this class. Due to the platform specificness + //of hash computations, we can't control the fact that computing a hash mutates + //state on some platforms such as windows (but that isn't a concern of this class. + auto md5HashResult = const_cast<AWSClient*>(this)->m_hash->Calculate(*body); + body->clear(); + if (md5HashResult.IsSuccess()) + { + httpRequest->SetHeaderValue(Http::CONTENT_MD5_HEADER, HashingUtils::Base64Encode(md5HashResult.GetResult())); + } + } +} + +Aws::String Aws::Client::GetAuthorizationHeader(const Aws::Http::HttpRequest& httpRequest) +{ + // Extract the hex-encoded signature from the authorization header rather than recalculating it. + assert(httpRequest.HasAwsAuthorization()); + const auto& authHeader = httpRequest.GetAwsAuthorization(); + auto signaturePosition = authHeader.rfind(Aws::Auth::SIGNATURE); + // The auth header should end with 'Signature=<64 chars>' + // Make sure we found the word 'Signature' in the header and make sure it's the last item followed by its 64 hex chars + if (signaturePosition == Aws::String::npos || (signaturePosition + strlen(Aws::Auth::SIGNATURE) + 1/*'=' character*/ + 64/*hex chars*/) != authHeader.length()) + { + AWS_LOGSTREAM_ERROR(AWS_CLIENT_LOG_TAG, "Failed to extract signature from authorization header."); + return {}; + } + return authHeader.substr(signaturePosition + strlen(Aws::Auth::SIGNATURE) + 1); +} + +void AWSClient::BuildHttpRequest(const Aws::AmazonWebServiceRequest& request, + const std::shared_ptr<HttpRequest>& httpRequest) const +{ + //do headers first since the request likely will set content-length as it's own header. + AddHeadersToRequest(httpRequest, request.GetHeaders()); + + if (request.IsEventStreamRequest()) + { + httpRequest->AddContentBody(request.GetBody()); + } + else + { + AddContentBodyToRequest(httpRequest, request.GetBody(), request.ShouldComputeContentMd5(), request.IsStreaming() && request.IsChunked() && m_httpClient->SupportsChunkedTransferEncoding()); + } + + // Pass along handlers for processing data sent/received in bytes + httpRequest->SetDataReceivedEventHandler(request.GetDataReceivedEventHandler()); + httpRequest->SetDataSentEventHandler(request.GetDataSentEventHandler()); + httpRequest->SetContinueRequestHandle(request.GetContinueRequestHandler()); + + request.AddQueryStringParameters(httpRequest->GetUri()); +} + +void AWSClient::AddCommonHeaders(HttpRequest& httpRequest) const +{ + httpRequest.SetUserAgent(m_userAgent); +} + +Aws::String AWSClient::GeneratePresignedUrl(URI& uri, HttpMethod method, long long expirationInSeconds) +{ + std::shared_ptr<HttpRequest> request = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); + if (signer->PresignRequest(*request, expirationInSeconds)) + { + return request->GetURIString(); + } + + return {}; +} + +Aws::String AWSClient::GeneratePresignedUrl(URI& uri, HttpMethod method, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds) +{ + std::shared_ptr<HttpRequest> request = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + for (const auto& it: customizedHeaders) + { + request->SetHeaderValue(it.first.c_str(), it.second); + } + auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); + if (signer->PresignRequest(*request, expirationInSeconds)) + { + return request->GetURIString(); + } + + return {}; +} + +Aws::String AWSClient::GeneratePresignedUrl(URI& uri, HttpMethod method, const char* region, long long expirationInSeconds) const +{ + std::shared_ptr<HttpRequest> request = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); + if (signer->PresignRequest(*request, region, expirationInSeconds)) + { + return request->GetURIString(); + } + + return {}; +} + +Aws::String AWSClient::GeneratePresignedUrl(URI& uri, HttpMethod method, const char* region, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds) +{ + std::shared_ptr<HttpRequest> request = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + for (const auto& it: customizedHeaders) + { + request->SetHeaderValue(it.first.c_str(), it.second); + } + auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); + if (signer->PresignRequest(*request, region, expirationInSeconds)) + { + return request->GetURIString(); + } + + return {}; +} + +Aws::String AWSClient::GeneratePresignedUrl(Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, long long expirationInSeconds) const +{ + std::shared_ptr<HttpRequest> request = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); + if (signer->PresignRequest(*request, region, serviceName, expirationInSeconds)) + { + return request->GetURIString(); + } + + return {}; +} + +Aws::String AWSClient::GeneratePresignedUrl(Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds) +{ + std::shared_ptr<HttpRequest> request = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + for (const auto& it: customizedHeaders) + { + request->SetHeaderValue(it.first.c_str(), it.second); + } + auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); + if (signer->PresignRequest(*request, region, serviceName, expirationInSeconds)) + { + return request->GetURIString(); + } + + return {}; +} + +Aws::String AWSClient::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, + const Aws::Http::QueryStringParameterCollection& extraParams, long long expirationInSeconds) const +{ + std::shared_ptr<HttpRequest> httpRequest = + ConvertToRequestForPresigning(request, uri, method, extraParams); + auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); + if (signer->PresignRequest(*httpRequest, region, expirationInSeconds)) + { + return httpRequest->GetURIString(); + } + + return {}; +} + +Aws::String AWSClient::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, +const Aws::Http::QueryStringParameterCollection& extraParams, long long expirationInSeconds) const +{ + std::shared_ptr<HttpRequest> httpRequest = + ConvertToRequestForPresigning(request, uri, method, extraParams); + auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); + if (signer->PresignRequest(*httpRequest, region, serviceName, expirationInSeconds)) + { + return httpRequest->GetURIString(); + } + + return {}; +} + +Aws::String AWSClient::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, Aws::Http::URI& uri, Aws::Http::HttpMethod method, + const Aws::Http::QueryStringParameterCollection& extraParams, long long expirationInSeconds) const +{ + std::shared_ptr<HttpRequest> httpRequest = + ConvertToRequestForPresigning(request, uri, method, extraParams); + auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); + if (signer->PresignRequest(*httpRequest, expirationInSeconds)) + { + return httpRequest->GetURIString(); + } + + return {}; +} + +std::shared_ptr<Aws::Http::HttpRequest> AWSClient::ConvertToRequestForPresigning(const Aws::AmazonWebServiceRequest& request, Aws::Http::URI& uri, + Aws::Http::HttpMethod method, const Aws::Http::QueryStringParameterCollection& extraParams) const +{ + request.PutToPresignedUrl(uri); + std::shared_ptr<HttpRequest> httpRequest = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + + for (auto& param : extraParams) + { + httpRequest->AddQueryStringParameter(param.first.c_str(), param.second); + } + + return httpRequest; +} + +std::shared_ptr<Aws::Http::HttpResponse> AWSClient::MakeHttpRequest(std::shared_ptr<Aws::Http::HttpRequest>& request) const +{ + return m_httpClient->MakeRequest(request, m_readRateLimiter.get(), m_writeRateLimiter.get()); +} + + +//////////////////////////////////////////////////////////////////////////// +AWSJsonClient::AWSJsonClient(const Aws::Client::ClientConfiguration& configuration, + const std::shared_ptr<Aws::Client::AWSAuthSigner>& signer, + const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller) : + BASECLASS(configuration, signer, errorMarshaller) +{ +} + +AWSJsonClient::AWSJsonClient(const Aws::Client::ClientConfiguration& configuration, + const std::shared_ptr<Aws::Auth::AWSAuthSignerProvider>& signerProvider, + const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller) : + BASECLASS(configuration, signerProvider, errorMarshaller) +{ +} + + +JsonOutcome AWSJsonClient::MakeRequest(const Aws::Http::URI& uri, + const Aws::AmazonWebServiceRequest& request, + Http::HttpMethod method, + const char* signerName, + const char* signerRegionOverride, + const char* signerServiceNameOverride) const +{ + HttpResponseOutcome httpOutcome(BASECLASS::AttemptExhaustively(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride)); + if (!httpOutcome.IsSuccess()) + { + return JsonOutcome(std::move(httpOutcome)); + } + + if (httpOutcome.GetResult()->GetResponseBody().tellp() > 0) + //this is stupid, but gcc doesn't pick up the covariant on the dereference so we have to give it a little hint. + return JsonOutcome(AmazonWebServiceResult<JsonValue>(JsonValue(httpOutcome.GetResult()->GetResponseBody()), + httpOutcome.GetResult()->GetHeaders(), + httpOutcome.GetResult()->GetResponseCode())); + + else + return JsonOutcome(AmazonWebServiceResult<JsonValue>(JsonValue(), httpOutcome.GetResult()->GetHeaders())); +} + +JsonOutcome AWSJsonClient::MakeRequest(const Aws::Http::URI& uri, + Http::HttpMethod method, + const char* signerName, + const char* requestName, + const char* signerRegionOverride, + const char* signerServiceNameOverride) const +{ + HttpResponseOutcome httpOutcome(BASECLASS::AttemptExhaustively(uri, method, signerName, requestName, signerRegionOverride, signerServiceNameOverride)); + if (!httpOutcome.IsSuccess()) + { + return JsonOutcome(std::move(httpOutcome)); + } + + if (httpOutcome.GetResult()->GetResponseBody().tellp() > 0) + { + JsonValue jsonValue(httpOutcome.GetResult()->GetResponseBody()); + if (!jsonValue.WasParseSuccessful()) + { + return JsonOutcome(AWSError<CoreErrors>(CoreErrors::UNKNOWN, "Json Parser Error", jsonValue.GetErrorMessage(), false)); + } + + //this is stupid, but gcc doesn't pick up the covariant on the dereference so we have to give it a little hint. + return JsonOutcome(AmazonWebServiceResult<JsonValue>(std::move(jsonValue), + httpOutcome.GetResult()->GetHeaders(), + httpOutcome.GetResult()->GetResponseCode())); + } + + return JsonOutcome(AmazonWebServiceResult<JsonValue>(JsonValue(), httpOutcome.GetResult()->GetHeaders())); +} + +JsonOutcome AWSJsonClient::MakeEventStreamRequest(std::shared_ptr<Aws::Http::HttpRequest>& request) const +{ + // request is assumed to be signed + std::shared_ptr<HttpResponse> httpResponse = MakeHttpRequest(request); + + if (DoesResponseGenerateError(httpResponse)) + { + AWS_LOGSTREAM_DEBUG(AWS_CLIENT_LOG_TAG, "Request returned error. Attempting to generate appropriate error codes from response"); + auto error = BuildAWSError(httpResponse); + return JsonOutcome(std::move(error)); + } + + AWS_LOGSTREAM_DEBUG(AWS_CLIENT_LOG_TAG, "Request returned successful response."); + + HttpResponseOutcome httpOutcome(std::move(httpResponse)); + + if (httpOutcome.GetResult()->GetResponseBody().tellp() > 0) + { + JsonValue jsonValue(httpOutcome.GetResult()->GetResponseBody()); + if (!jsonValue.WasParseSuccessful()) + { + return JsonOutcome(AWSError<CoreErrors>(CoreErrors::UNKNOWN, "Json Parser Error", jsonValue.GetErrorMessage(), false)); + } + + //this is stupid, but gcc doesn't pick up the covariant on the dereference so we have to give it a little hint. + return JsonOutcome(AmazonWebServiceResult<JsonValue>(std::move(jsonValue), + httpOutcome.GetResult()->GetHeaders(), + httpOutcome.GetResult()->GetResponseCode())); + } + + return JsonOutcome(AmazonWebServiceResult<JsonValue>(JsonValue(), httpOutcome.GetResult()->GetHeaders())); +} + +AWSError<CoreErrors> AWSJsonClient::BuildAWSError( + const std::shared_ptr<Aws::Http::HttpResponse>& httpResponse) const +{ + AWSError<CoreErrors> error; + if (httpResponse->HasClientError()) + { + bool retryable = httpResponse->GetClientErrorType() == CoreErrors::NETWORK_CONNECTION ? true : false; + error = AWSError<CoreErrors>(httpResponse->GetClientErrorType(), "", httpResponse->GetClientErrorMessage(), retryable); + } + else if (!httpResponse->GetResponseBody() || httpResponse->GetResponseBody().tellp() < 1) + { + auto responseCode = httpResponse->GetResponseCode(); + auto errorCode = GuessBodylessErrorType(responseCode); + + Aws::StringStream ss; + ss << "No response body."; + error = AWSError<CoreErrors>(errorCode, "", ss.str(), + IsRetryableHttpResponseCode(responseCode)); + } + else + { + assert(httpResponse->GetResponseCode() != HttpResponseCode::OK); + error = GetErrorMarshaller()->Marshall(*httpResponse); + } + + error.SetResponseHeaders(httpResponse->GetHeaders()); + error.SetResponseCode(httpResponse->GetResponseCode()); + error.SetRemoteHostIpAddress(httpResponse->GetOriginatingRequest().GetResolvedRemoteHost()); + AWS_LOGSTREAM_ERROR(AWS_CLIENT_LOG_TAG, error); + return error; +} + +///////////////////////////////////////////////////////////////////////////////////////// +AWSXMLClient::AWSXMLClient(const Aws::Client::ClientConfiguration& configuration, + const std::shared_ptr<Aws::Client::AWSAuthSigner>& signer, + const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller) : + BASECLASS(configuration, signer, errorMarshaller) +{ +} + +AWSXMLClient::AWSXMLClient(const Aws::Client::ClientConfiguration& configuration, + const std::shared_ptr<Aws::Auth::AWSAuthSignerProvider>& signerProvider, + const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller) : + BASECLASS(configuration, signerProvider, errorMarshaller) +{ +} + +XmlOutcome AWSXMLClient::MakeRequest(const Aws::Http::URI& uri, + const Aws::AmazonWebServiceRequest& request, + Http::HttpMethod method, + const char* signerName, + const char* signerRegionOverride, + const char* signerServiceNameOverride) const +{ + HttpResponseOutcome httpOutcome(BASECLASS::AttemptExhaustively(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride)); + if (!httpOutcome.IsSuccess()) + { + return XmlOutcome(std::move(httpOutcome)); + } + + if (httpOutcome.GetResult()->GetResponseBody().tellp() > 0) + { + XmlDocument xmlDoc = XmlDocument::CreateFromXmlStream(httpOutcome.GetResult()->GetResponseBody()); + + if (!xmlDoc.WasParseSuccessful()) + { + AWS_LOGSTREAM_ERROR(AWS_CLIENT_LOG_TAG, "Xml parsing for error failed with message " << xmlDoc.GetErrorMessage().c_str()); + return AWSError<CoreErrors>(CoreErrors::UNKNOWN, "Xml Parse Error", xmlDoc.GetErrorMessage(), false); + } + + return XmlOutcome(AmazonWebServiceResult<XmlDocument>(std::move(xmlDoc), + httpOutcome.GetResult()->GetHeaders(), httpOutcome.GetResult()->GetResponseCode())); + } + + return XmlOutcome(AmazonWebServiceResult<XmlDocument>(XmlDocument(), httpOutcome.GetResult()->GetHeaders())); +} + +XmlOutcome AWSXMLClient::MakeRequest(const Aws::Http::URI& uri, + Http::HttpMethod method, + const char* signerName, + const char* requestName, + const char* signerRegionOverride, + const char* signerServiceNameOverride) const +{ + HttpResponseOutcome httpOutcome(BASECLASS::AttemptExhaustively(uri, method, signerName, requestName, signerRegionOverride, signerServiceNameOverride)); + if (!httpOutcome.IsSuccess()) + { + return XmlOutcome(std::move(httpOutcome)); + } + + if (httpOutcome.GetResult()->GetResponseBody().tellp() > 0) + { + return XmlOutcome(AmazonWebServiceResult<XmlDocument>( + XmlDocument::CreateFromXmlStream(httpOutcome.GetResult()->GetResponseBody()), + httpOutcome.GetResult()->GetHeaders(), httpOutcome.GetResult()->GetResponseCode())); + } + + return XmlOutcome(AmazonWebServiceResult<XmlDocument>(XmlDocument(), httpOutcome.GetResult()->GetHeaders())); +} + +AWSError<CoreErrors> AWSXMLClient::BuildAWSError(const std::shared_ptr<Http::HttpResponse>& httpResponse) const +{ + AWSError<CoreErrors> error; + if (httpResponse->HasClientError()) + { + bool retryable = httpResponse->GetClientErrorType() == CoreErrors::NETWORK_CONNECTION ? true : false; + error = AWSError<CoreErrors>(httpResponse->GetClientErrorType(), "", httpResponse->GetClientErrorMessage(), retryable); + } + else if (!httpResponse->GetResponseBody() || httpResponse->GetResponseBody().tellp() < 1) + { + auto responseCode = httpResponse->GetResponseCode(); + auto errorCode = GuessBodylessErrorType(responseCode); + + Aws::StringStream ss; + ss << "No response body."; + error = AWSError<CoreErrors>(errorCode, "", ss.str(), IsRetryableHttpResponseCode(responseCode)); + } + else + { + assert(httpResponse->GetResponseCode() != HttpResponseCode::OK); + + // When trying to build an AWS Error from a response which is an FStream, we need to rewind the + // file pointer back to the beginning in order to correctly read the input using the XML string iterator + if ((httpResponse->GetResponseBody().tellp() > 0) + && (httpResponse->GetResponseBody().tellg() > 0)) + { + httpResponse->GetResponseBody().seekg(0); + } + + error = GetErrorMarshaller()->Marshall(*httpResponse); + } + + error.SetResponseHeaders(httpResponse->GetHeaders()); + error.SetResponseCode(httpResponse->GetResponseCode()); + error.SetRemoteHostIpAddress(httpResponse->GetOriginatingRequest().GetResolvedRemoteHost()); + AWS_LOGSTREAM_ERROR(AWS_CLIENT_LOG_TAG, error); + return error; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSErrorMarshaller.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSErrorMarshaller.cpp new file mode 100644 index 0000000000..f5fa676f98 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSErrorMarshaller.cpp @@ -0,0 +1,180 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/client/AWSErrorMarshaller.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/json/JsonSerializer.h> +#include <aws/core/utils/xml/XmlSerializer.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/client/AWSError.h> +#include <aws/core/client/CoreErrors.h> + +using namespace Aws::Utils::Logging; +using namespace Aws::Utils::Json; +using namespace Aws::Utils::Xml; +using namespace Aws::Http; +using namespace Aws::Utils; +using namespace Aws::Client; + +static const char AWS_ERROR_MARSHALLER_LOG_TAG[] = "AWSErrorMarshaller"; +AWS_CORE_API extern const char MESSAGE_LOWER_CASE[] = "message"; +AWS_CORE_API extern const char MESSAGE_CAMEL_CASE[] = "Message"; +AWS_CORE_API extern const char ERROR_TYPE_HEADER[] = "x-amzn-ErrorType"; +AWS_CORE_API extern const char REQUEST_ID_HEADER[] = "x-amzn-RequestId"; +AWS_CORE_API extern const char TYPE[] = "__type"; + +AWSError<CoreErrors> JsonErrorMarshaller::Marshall(const Aws::Http::HttpResponse& httpResponse) const +{ + JsonValue exceptionPayload(httpResponse.GetResponseBody()); + JsonView payloadView(exceptionPayload); + AWSError<CoreErrors> error; + if (exceptionPayload.WasParseSuccessful()) + { + AWS_LOGSTREAM_TRACE(AWS_ERROR_MARSHALLER_LOG_TAG, "Error response is " << payloadView.WriteReadable()); + + Aws::String message(payloadView.ValueExists(MESSAGE_CAMEL_CASE) ? payloadView.GetString(MESSAGE_CAMEL_CASE) : + payloadView.ValueExists(MESSAGE_LOWER_CASE) ? payloadView.GetString(MESSAGE_LOWER_CASE) : ""); + + if (httpResponse.HasHeader(ERROR_TYPE_HEADER)) + { + error = Marshall(httpResponse.GetHeader(ERROR_TYPE_HEADER), message); + } + else if (payloadView.ValueExists(TYPE)) + { + error = Marshall(payloadView.GetString(TYPE), message); + } + else + { + error = FindErrorByHttpResponseCode(httpResponse.GetResponseCode()); + error.SetMessage(message); + } + } + else + { + error = AWSError<CoreErrors>(CoreErrors::UNKNOWN, "", "Failed to parse error payload", false); + } + + error.SetRequestId(httpResponse.HasHeader(REQUEST_ID_HEADER) ? httpResponse.GetHeader(REQUEST_ID_HEADER) : ""); + error.SetJsonPayload(std::move(exceptionPayload)); + return error; +} + +const JsonValue& JsonErrorMarshaller::GetJsonPayloadFromError(const AWSError<CoreErrors>& error) const +{ + return error.GetJsonPayload(); +} + +AWSError<CoreErrors> XmlErrorMarshaller::Marshall(const Aws::Http::HttpResponse& httpResponse) const +{ + XmlDocument doc = XmlDocument::CreateFromXmlStream(httpResponse.GetResponseBody()); + AWS_LOGSTREAM_TRACE(AWS_ERROR_MARSHALLER_LOG_TAG, "Error response is " << doc.ConvertToString()); + bool errorParsed = false; + AWSError<CoreErrors> error; + if (doc.WasParseSuccessful() && !doc.GetRootElement().IsNull()) + { + XmlNode errorNode = doc.GetRootElement(); + + Aws::String requestId(!errorNode.FirstChild("RequestId").IsNull() ? errorNode.FirstChild("RequestId").GetText() : + !errorNode.FirstChild("RequestID").IsNull() ? errorNode.FirstChild("RequestID").GetText() : ""); + + if (errorNode.GetName() != "Error") + { + errorNode = doc.GetRootElement().FirstChild("Error"); + } + if (errorNode.IsNull()) + { + errorNode = doc.GetRootElement().FirstChild("Errors"); + if(!errorNode.IsNull()) + { + errorNode = errorNode.FirstChild("Error"); + } + } + + if (!errorNode.IsNull()) + { + requestId = !requestId.empty() ? requestId : !errorNode.FirstChild("RequestId").IsNull() ? errorNode.FirstChild("RequestId").GetText() : + !errorNode.FirstChild("RequestID").IsNull() ? errorNode.FirstChild("RequestID").GetText() : ""; + + XmlNode codeNode = errorNode.FirstChild("Code"); + XmlNode messageNode = errorNode.FirstChild("Message"); + + if (!codeNode.IsNull()) + { + error = Marshall(StringUtils::Trim(codeNode.GetText().c_str()), + StringUtils::Trim(messageNode.GetText().c_str())); + errorParsed = true; + } + } + + error.SetRequestId(requestId); + } + + if(!errorParsed) + { + // An error occurred attempting to parse the httpResponse as an XML stream, so we're just + // going to dump the XML parsing error and the http response code as a string + AWS_LOGSTREAM_WARN(AWS_ERROR_MARSHALLER_LOG_TAG, "Unable to generate a proper httpResponse from the response " + "stream. Response code: " << static_cast< uint32_t >(httpResponse.GetResponseCode())); + error = FindErrorByHttpResponseCode(httpResponse.GetResponseCode()); + } + + error.SetXmlPayload(std::move(doc)); + return error; +} + +const XmlDocument& XmlErrorMarshaller::GetXmlPayloadFromError(const AWSError<CoreErrors>& error) const +{ + return error.GetXmlPayload(); +} + +AWSError<CoreErrors> AWSErrorMarshaller::Marshall(const Aws::String& exceptionName, const Aws::String& message) const +{ + if(exceptionName.empty()) + { + return AWSError<CoreErrors>(CoreErrors::UNKNOWN, "", message, false); + } + + auto locationOfPound = exceptionName.find_first_of('#'); + auto locationOfColon = exceptionName.find_first_of(':'); + Aws::String formalExceptionName; + + if (locationOfPound != Aws::String::npos) + { + formalExceptionName = exceptionName.substr(locationOfPound + 1); + } + else if (locationOfColon != Aws::String::npos) + { + formalExceptionName = exceptionName.substr(0, locationOfColon); + } + else + { + formalExceptionName = exceptionName; + } + + AWSError<CoreErrors> error = FindErrorByName(formalExceptionName.c_str()); + if (error.GetErrorType() != CoreErrors::UNKNOWN) + { + AWS_LOGSTREAM_WARN(AWS_ERROR_MARSHALLER_LOG_TAG, "Encountered AWSError '" << formalExceptionName.c_str() << + "': " << message.c_str()); + error.SetExceptionName(formalExceptionName); + error.SetMessage(message); + return error; + } + + AWS_LOGSTREAM_WARN(AWS_ERROR_MARSHALLER_LOG_TAG, "Encountered Unknown AWSError '" << exceptionName.c_str() << + "': " << message.c_str()); + + return AWSError<CoreErrors>(CoreErrors::UNKNOWN, exceptionName, "Unable to parse ExceptionName: " + exceptionName + " Message: " + message, false); +} + +AWSError<CoreErrors> AWSErrorMarshaller::FindErrorByName(const char* errorName) const +{ + return CoreErrorsMapper::GetErrorForName(errorName); +} + +AWSError<CoreErrors> AWSErrorMarshaller::FindErrorByHttpResponseCode(Aws::Http::HttpResponseCode code) const +{ + return CoreErrorsMapper::GetErrorForHttpResponseCode(code); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AsyncCallerContext.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AsyncCallerContext.cpp new file mode 100644 index 0000000000..4f9abdc9e4 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AsyncCallerContext.cpp @@ -0,0 +1,16 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/client/AsyncCallerContext.h> +#include <aws/core/utils/UUID.h> + +namespace Aws +{ + namespace Client + { + AsyncCallerContext::AsyncCallerContext() : m_uuid(Aws::Utils::UUID::RandomUUID()) + {} + } +}
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp new file mode 100644 index 0000000000..e517379a77 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp @@ -0,0 +1,160 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/client/ClientConfiguration.h> +#include <aws/core/auth/AWSCredentialsProvider.h> +#include <aws/core/client/DefaultRetryStrategy.h> +#include <aws/core/platform/Environment.h> +#include <aws/core/platform/OSVersionInfo.h> +#include <aws/core/utils/memory/AWSMemory.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/threading/Executor.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> +#include <aws/core/Version.h> +#include <aws/core/config/AWSProfileConfigLoader.h> +#include <aws/core/utils/logging/LogMacros.h> + +namespace Aws +{ +namespace Auth +{ + AWS_CORE_API Aws::String GetConfigProfileFilename(); +} +namespace Client +{ + +static const char* CLIENT_CONFIG_TAG = "ClientConfiguration"; + +AWS_CORE_API Aws::String ComputeUserAgentString() +{ + Aws::StringStream ss; + ss << "aws-sdk-cpp/" << Version::GetVersionString() << " " << Aws::OSVersionInfo::ComputeOSVersionString() + << " " << Version::GetCompilerVersionString(); + return ss.str(); +} + +ClientConfiguration::ClientConfiguration() : + scheme(Aws::Http::Scheme::HTTPS), + useDualStack(false), + maxConnections(25), + httpRequestTimeoutMs(0), + requestTimeoutMs(3000), + connectTimeoutMs(1000), + enableTcpKeepAlive(true), + tcpKeepAliveIntervalMs(30000), + lowSpeedLimit(1), + proxyScheme(Aws::Http::Scheme::HTTP), + proxyPort(0), + executor(Aws::MakeShared<Aws::Utils::Threading::DefaultExecutor>(CLIENT_CONFIG_TAG)), + verifySSL(true), + writeRateLimiter(nullptr), + readRateLimiter(nullptr), + httpLibOverride(Aws::Http::TransferLibType::DEFAULT_CLIENT), + followRedirects(FollowRedirectsPolicy::DEFAULT), + disableExpectHeader(false), + enableClockSkewAdjustment(true), + enableHostPrefixInjection(true), + enableEndpointDiscovery(false), + profileName(Aws::Auth::GetConfigProfileName()) +{ + AWS_LOGSTREAM_DEBUG(CLIENT_CONFIG_TAG, "ClientConfiguration will use SDK Auto Resolved profile: [" << profileName << "] if not specified by users."); + + // Initialize Retry Strategy + int maxAttempts; + Aws::String maxAttemptsString = Aws::Environment::GetEnv("AWS_MAX_ATTEMPTS"); + if (maxAttemptsString.empty()) + { + maxAttemptsString = Aws::Config::GetCachedConfigValue("max_attempts"); + } + // In case users specify 0 explicitly to disable retry. + if (maxAttemptsString == "0") + { + maxAttempts = 0; + } + else + { + maxAttempts = static_cast<int>(Aws::Utils::StringUtils::ConvertToInt32(maxAttemptsString.c_str())); + if (maxAttempts == 0) + { + AWS_LOGSTREAM_WARN(CLIENT_CONFIG_TAG, "Retry Strategy will use the default max attempts."); + maxAttempts = -1; + } + } + + Aws::String retryMode = Aws::Environment::GetEnv("AWS_RETRY_MODE"); + if (retryMode.empty()) + { + retryMode = Aws::Config::GetCachedConfigValue("retry_mode"); + } + if (retryMode == "standard") + { + if (maxAttempts < 0) + { + retryStrategy = Aws::MakeShared<StandardRetryStrategy>(CLIENT_CONFIG_TAG); + } + else + { + retryStrategy = Aws::MakeShared<StandardRetryStrategy>(CLIENT_CONFIG_TAG, maxAttempts); + } + } + else + { + retryStrategy = Aws::MakeShared<DefaultRetryStrategy>(CLIENT_CONFIG_TAG); + } + + // Automatically determine the AWS region from environment variables, configuration file and EC2 metadata. + region = Aws::Environment::GetEnv("AWS_DEFAULT_REGION"); + if (!region.empty()) + { + return; + } + + region = Aws::Environment::GetEnv("AWS_REGION"); + if (!region.empty()) + { + return; + } + + region = Aws::Config::GetCachedConfigValue("region"); + if (!region.empty()) + { + return; + } + + if (Aws::Utils::StringUtils::ToLower(Aws::Environment::GetEnv("AWS_EC2_METADATA_DISABLED").c_str()) != "true") + { + auto client = Aws::Internal::GetEC2MetadataClient(); + if (client) + { + region = client->GetCurrentRegion(); + } + } + + if (!region.empty()) + { + return; + } + + region = Aws::String(Aws::Region::US_EAST_1); +} + +ClientConfiguration::ClientConfiguration(const char* profile) : ClientConfiguration() +{ + if (profile && Aws::Config::HasCachedConfigProfile(profile)) + { + this->profileName = Aws::String(profile); + AWS_LOGSTREAM_DEBUG(CLIENT_CONFIG_TAG, "Use user specified profile: [" << this->profileName << "] for ClientConfiguration."); + auto tmpRegion = Aws::Config::GetCachedConfigProfile(this->profileName).GetRegion(); + if (!tmpRegion.empty()) + { + region = tmpRegion; + } + return; + } + AWS_LOGSTREAM_WARN(CLIENT_CONFIG_TAG, "User specified profile: [" << profile << "] is not found, will use the SDK resolved one."); +} + +} // namespace Client +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/CoreErrors.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/CoreErrors.cpp new file mode 100644 index 0000000000..8c2c288dcd --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/CoreErrors.cpp @@ -0,0 +1,151 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/client/AWSError.h> +#include <aws/core/client/CoreErrors.h> +#include <aws/core/utils/memory/stl/AWSMap.h> +#include <aws/core/utils/HashingUtils.h> + +using namespace Aws::Client; +using namespace Aws::Utils; +using namespace Aws::Http; + +#ifdef _MSC_VER +#pragma warning(push) +// VS2015 compiler's bug, warning s_CoreErrorsMapper: symbol will be dynamically initialized (implementation limitation) +#pragma warning(disable : 4592) +#endif + +static Aws::UniquePtr<Aws::Map<Aws::String, AWSError<CoreErrors> > > s_CoreErrorsMapper(nullptr); + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +void CoreErrorsMapper::InitCoreErrorsMapper() +{ + if (s_CoreErrorsMapper) + { + return; + } + s_CoreErrorsMapper = Aws::MakeUnique<Aws::Map<Aws::String, AWSError<CoreErrors> > >("InitCoreErrorsMapper"); + + s_CoreErrorsMapper->emplace("IncompleteSignature", AWSError<CoreErrors>(CoreErrors::INCOMPLETE_SIGNATURE, false)); + s_CoreErrorsMapper->emplace("IncompleteSignatureException", AWSError<CoreErrors>(CoreErrors::INCOMPLETE_SIGNATURE, false)); + s_CoreErrorsMapper->emplace("InvalidSignatureException", AWSError<CoreErrors>(CoreErrors::INVALID_SIGNATURE, false)); + s_CoreErrorsMapper->emplace("InvalidSignature", AWSError<CoreErrors>(CoreErrors::INVALID_SIGNATURE, false)); + s_CoreErrorsMapper->emplace("InternalFailureException", AWSError<CoreErrors>(CoreErrors::INTERNAL_FAILURE, true)); + s_CoreErrorsMapper->emplace("InternalFailure", AWSError<CoreErrors>(CoreErrors::INTERNAL_FAILURE, true)); + s_CoreErrorsMapper->emplace("InternalServerError", AWSError<CoreErrors>(CoreErrors::INTERNAL_FAILURE, true)); + s_CoreErrorsMapper->emplace("InternalError", AWSError<CoreErrors>(CoreErrors::INTERNAL_FAILURE, true)); + s_CoreErrorsMapper->emplace("InvalidActionException", AWSError<CoreErrors>(CoreErrors::INVALID_ACTION, false)); + s_CoreErrorsMapper->emplace("InvalidAction", AWSError<CoreErrors>(CoreErrors::INVALID_ACTION, false)); + s_CoreErrorsMapper->emplace("InvalidClientTokenIdException", AWSError<CoreErrors>(CoreErrors::INVALID_CLIENT_TOKEN_ID, false)); + s_CoreErrorsMapper->emplace("InvalidClientTokenId", AWSError<CoreErrors>(CoreErrors::INVALID_CLIENT_TOKEN_ID, false)); + s_CoreErrorsMapper->emplace("InvalidParameterCombinationException", AWSError<CoreErrors>(CoreErrors::INVALID_PARAMETER_COMBINATION, false)); + s_CoreErrorsMapper->emplace("InvalidParameterCombination", AWSError<CoreErrors>(CoreErrors::INVALID_PARAMETER_COMBINATION, false)); + s_CoreErrorsMapper->emplace("InvalidParameterValueException", AWSError<CoreErrors>(CoreErrors::INVALID_PARAMETER_VALUE, false)); + s_CoreErrorsMapper->emplace("InvalidParameterValue", AWSError<CoreErrors>(CoreErrors::INVALID_PARAMETER_VALUE, false)); + s_CoreErrorsMapper->emplace("InvalidQueryParameterException", AWSError<CoreErrors>(CoreErrors::INVALID_QUERY_PARAMETER, false)); + s_CoreErrorsMapper->emplace("InvalidQueryParameter", AWSError<CoreErrors>(CoreErrors::INVALID_QUERY_PARAMETER, false)); + s_CoreErrorsMapper->emplace("MalformedQueryStringException", AWSError<CoreErrors>(CoreErrors::MALFORMED_QUERY_STRING, false)); + s_CoreErrorsMapper->emplace("MalformedQueryString", AWSError<CoreErrors>(CoreErrors::MALFORMED_QUERY_STRING, false)); + s_CoreErrorsMapper->emplace("MissingActionException", AWSError<CoreErrors>(CoreErrors::MISSING_ACTION, false)); + s_CoreErrorsMapper->emplace("MissingAction", AWSError<CoreErrors>(CoreErrors::MISSING_ACTION, false)); + s_CoreErrorsMapper->emplace("MissingAuthenticationTokenException", AWSError<CoreErrors>(CoreErrors::MISSING_AUTHENTICATION_TOKEN, false)); + s_CoreErrorsMapper->emplace("MissingAuthenticationToken", AWSError<CoreErrors>(CoreErrors::MISSING_AUTHENTICATION_TOKEN, false)); + s_CoreErrorsMapper->emplace("MissingParameterException", AWSError<CoreErrors>(CoreErrors::MISSING_PARAMETER, false)); + s_CoreErrorsMapper->emplace("MissingParameter", AWSError<CoreErrors>(CoreErrors::MISSING_PARAMETER, false)); + s_CoreErrorsMapper->emplace("OptInRequired", AWSError<CoreErrors>(CoreErrors::OPT_IN_REQUIRED, false)); + s_CoreErrorsMapper->emplace("RequestExpiredException", AWSError<CoreErrors>(CoreErrors::REQUEST_EXPIRED, true)); + s_CoreErrorsMapper->emplace("RequestExpired", AWSError<CoreErrors>(CoreErrors::REQUEST_EXPIRED, true)); + s_CoreErrorsMapper->emplace("ServiceUnavailableException", AWSError<CoreErrors>(CoreErrors::SERVICE_UNAVAILABLE, true)); + s_CoreErrorsMapper->emplace("ServiceUnavailableError", AWSError<CoreErrors>(CoreErrors::SERVICE_UNAVAILABLE, true)); + s_CoreErrorsMapper->emplace("ServiceUnavailable", AWSError<CoreErrors>(CoreErrors::SERVICE_UNAVAILABLE, true)); + s_CoreErrorsMapper->emplace("RequestThrottledException", AWSError<CoreErrors>(CoreErrors::THROTTLING, true)); + s_CoreErrorsMapper->emplace("RequestThrottled", AWSError<CoreErrors>(CoreErrors::THROTTLING, true)); + s_CoreErrorsMapper->emplace("ThrottlingException", AWSError<CoreErrors>(CoreErrors::THROTTLING, true)); + s_CoreErrorsMapper->emplace("ThrottledException", AWSError<CoreErrors>(CoreErrors::THROTTLING, true)); + s_CoreErrorsMapper->emplace("Throttling", AWSError<CoreErrors>(CoreErrors::THROTTLING, true)); + s_CoreErrorsMapper->emplace("ValidationErrorException", AWSError<CoreErrors>(CoreErrors::VALIDATION, false)); + s_CoreErrorsMapper->emplace("ValidationException", AWSError<CoreErrors>(CoreErrors::VALIDATION, false)); + s_CoreErrorsMapper->emplace("ValidationError", AWSError<CoreErrors>(CoreErrors::VALIDATION, false)); + s_CoreErrorsMapper->emplace("AccessDeniedException", AWSError<CoreErrors>(CoreErrors::ACCESS_DENIED, false)); + s_CoreErrorsMapper->emplace("AccessDenied", AWSError<CoreErrors>(CoreErrors::ACCESS_DENIED, false)); + s_CoreErrorsMapper->emplace("ResourceNotFoundException", AWSError<CoreErrors>(CoreErrors::RESOURCE_NOT_FOUND, false)); + s_CoreErrorsMapper->emplace("ResourceNotFound", AWSError<CoreErrors>(CoreErrors::RESOURCE_NOT_FOUND, false)); + s_CoreErrorsMapper->emplace("UnrecognizedClientException", AWSError<CoreErrors>(CoreErrors::UNRECOGNIZED_CLIENT, false)); + s_CoreErrorsMapper->emplace("UnrecognizedClient", AWSError<CoreErrors>(CoreErrors::UNRECOGNIZED_CLIENT, false)); + s_CoreErrorsMapper->emplace("SlowDownException", AWSError<CoreErrors>(CoreErrors::SLOW_DOWN, true)); + s_CoreErrorsMapper->emplace("SlowDown", AWSError<CoreErrors>(CoreErrors::SLOW_DOWN, true)); + s_CoreErrorsMapper->emplace("SignatureDoesNotMatchException", AWSError<CoreErrors>(CoreErrors::SIGNATURE_DOES_NOT_MATCH, false)); + s_CoreErrorsMapper->emplace("SignatureDoesNotMatch", AWSError<CoreErrors>(CoreErrors::SIGNATURE_DOES_NOT_MATCH, false)); + s_CoreErrorsMapper->emplace("InvalidAccessKeyIdException", AWSError<CoreErrors>(CoreErrors::INVALID_ACCESS_KEY_ID, false)); + s_CoreErrorsMapper->emplace("InvalidAccessKeyId", AWSError<CoreErrors>(CoreErrors::INVALID_ACCESS_KEY_ID, false)); + s_CoreErrorsMapper->emplace("RequestTimeTooSkewedException", AWSError<CoreErrors>(CoreErrors::REQUEST_TIME_TOO_SKEWED, true)); + s_CoreErrorsMapper->emplace("RequestTimeTooSkewed", AWSError<CoreErrors>(CoreErrors::REQUEST_TIME_TOO_SKEWED, true)); + s_CoreErrorsMapper->emplace("RequestTimeoutException", AWSError<CoreErrors>(CoreErrors::REQUEST_TIMEOUT, true)); + s_CoreErrorsMapper->emplace("RequestTimeout", AWSError<CoreErrors>(CoreErrors::REQUEST_TIMEOUT, true)); +} + +void CoreErrorsMapper::CleanupCoreErrorsMapper() +{ + if (s_CoreErrorsMapper) + { + s_CoreErrorsMapper = nullptr; + } +} + +AWSError<CoreErrors> CoreErrorsMapper::GetErrorForName(const char* errorName) +{ + auto iter = s_CoreErrorsMapper->find(errorName); + if (iter != s_CoreErrorsMapper->end()) + { + return iter->second; + } + return AWSError<CoreErrors>(CoreErrors::UNKNOWN, false); +} + +AWS_CORE_API AWSError<CoreErrors> CoreErrorsMapper::GetErrorForHttpResponseCode(HttpResponseCode code) +{ + // best effort attempt to map HTTP response codes to CoreErrors + bool retryable = IsRetryableHttpResponseCode(code); + AWSError<CoreErrors> error; + switch (code) + { + case HttpResponseCode::UNAUTHORIZED: + case HttpResponseCode::FORBIDDEN: + error = AWSError<CoreErrors>(CoreErrors::ACCESS_DENIED, retryable); + break; + case HttpResponseCode::NOT_FOUND: + error = AWSError<CoreErrors>(CoreErrors::RESOURCE_NOT_FOUND, retryable); + break; + case HttpResponseCode::TOO_MANY_REQUESTS: + error = AWSError<CoreErrors>(CoreErrors::SLOW_DOWN, retryable); + break; + case HttpResponseCode::INTERNAL_SERVER_ERROR: + error = AWSError<CoreErrors>(CoreErrors::INTERNAL_FAILURE, retryable); + break; + case HttpResponseCode::BANDWIDTH_LIMIT_EXCEEDED: + error = AWSError<CoreErrors>(CoreErrors::THROTTLING, retryable); + break; + case HttpResponseCode::SERVICE_UNAVAILABLE: + error = AWSError<CoreErrors>(CoreErrors::SERVICE_UNAVAILABLE, retryable); + break; + case HttpResponseCode::REQUEST_TIMEOUT: + case HttpResponseCode::AUTHENTICATION_TIMEOUT: + case HttpResponseCode::LOGIN_TIMEOUT: + case HttpResponseCode::GATEWAY_TIMEOUT: + case HttpResponseCode::NETWORK_READ_TIMEOUT: + case HttpResponseCode::NETWORK_CONNECT_TIMEOUT: + error = AWSError<CoreErrors>(CoreErrors::REQUEST_TIMEOUT, retryable); + break; + default: + int codeValue = static_cast<int>(code); + error = AWSError<CoreErrors>(CoreErrors::UNKNOWN, codeValue >= 500 && codeValue < 600); + } + error.SetResponseCode(code); + return error; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/DefaultRetryStrategy.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/DefaultRetryStrategy.cpp new file mode 100644 index 0000000000..7e57c79ffc --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/DefaultRetryStrategy.cpp @@ -0,0 +1,32 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/client/DefaultRetryStrategy.h> + +#include <aws/core/client/AWSError.h> +#include <aws/core/utils/UnreferencedParam.h> + +using namespace Aws; +using namespace Aws::Client; + +bool DefaultRetryStrategy::ShouldRetry(const AWSError<CoreErrors>& error, long attemptedRetries) const +{ + if (attemptedRetries >= m_maxRetries) + return false; + + return error.ShouldRetry(); +} + +long DefaultRetryStrategy::CalculateDelayBeforeNextRetry(const AWSError<CoreErrors>& error, long attemptedRetries) const +{ + AWS_UNREFERENCED_PARAM(error); + + if (attemptedRetries == 0) + { + return 0; + } + + return (1 << attemptedRetries) * m_scaleFactor; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/RetryStrategy.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/RetryStrategy.cpp new file mode 100644 index 0000000000..b439b7ca99 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/RetryStrategy.cpp @@ -0,0 +1,102 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/client/RetryStrategy.h> + +#include <aws/core/client/AWSError.h> +#include <aws/core/client/CoreErrors.h> +#include <aws/core/utils/Outcome.h> + +using namespace Aws::Utils::Threading; + +namespace Aws +{ + namespace Client + { + static const int INITIAL_RETRY_TOKENS = 500; + static const int RETRY_COST = 5; + static const int NO_RETRY_INCREMENT = 1; + static const int TIMEOUT_RETRY_COST = 10; + + StandardRetryStrategy::StandardRetryStrategy(long maxAttempts) : + m_retryQuotaContainer(Aws::MakeShared<DefaultRetryQuotaContainer>("StandardRetryStrategy")), + m_maxAttempts(maxAttempts) + {} + + StandardRetryStrategy::StandardRetryStrategy(std::shared_ptr<RetryQuotaContainer> retryQuotaContainer, long maxAttempts) : + m_retryQuotaContainer(retryQuotaContainer), + m_maxAttempts(maxAttempts) + {} + + void StandardRetryStrategy::RequestBookkeeping(const HttpResponseOutcome& httpResponseOutcome) + { + if (httpResponseOutcome.IsSuccess()) + { + m_retryQuotaContainer->ReleaseRetryQuota(NO_RETRY_INCREMENT); + } + } + + void StandardRetryStrategy::RequestBookkeeping(const HttpResponseOutcome& httpResponseOutcome, const AWSError<CoreErrors>& lastError) + { + if (httpResponseOutcome.IsSuccess()) + { + m_retryQuotaContainer->ReleaseRetryQuota(lastError); + } + } + + bool StandardRetryStrategy::ShouldRetry(const AWSError<CoreErrors>& error, long attemptedRetries) const + { + if (!error.ShouldRetry()) + return false; + + if (attemptedRetries + 1 >= m_maxAttempts) + return false; + + return m_retryQuotaContainer->AcquireRetryQuota(error); + } + + long StandardRetryStrategy::CalculateDelayBeforeNextRetry(const AWSError<CoreErrors>& error, long attemptedRetries) const + { + AWS_UNREFERENCED_PARAM(error); + return (std::min)(rand() % 1000 * (1 << attemptedRetries), 20000); + } + + DefaultRetryQuotaContainer::DefaultRetryQuotaContainer() : m_retryQuota(INITIAL_RETRY_TOKENS) + {} + + bool DefaultRetryQuotaContainer::AcquireRetryQuota(int capacityAmount) + { + WriterLockGuard guard(m_retryQuotaLock); + + if (capacityAmount > m_retryQuota) + { + return false; + } + else + { + m_retryQuota -= capacityAmount; + return true; + } + } + + bool DefaultRetryQuotaContainer::AcquireRetryQuota(const AWSError<CoreErrors>& error) + { + int capacityAmount = error.GetErrorType() == CoreErrors::REQUEST_TIMEOUT ? TIMEOUT_RETRY_COST : RETRY_COST; + return AcquireRetryQuota(capacityAmount); + } + + void DefaultRetryQuotaContainer::ReleaseRetryQuota(int capacityAmount) + { + WriterLockGuard guard(m_retryQuotaLock); + m_retryQuota = (std::min)(m_retryQuota + capacityAmount, INITIAL_RETRY_TOKENS); + } + + void DefaultRetryQuotaContainer::ReleaseRetryQuota(const AWSError<CoreErrors>& error) + { + int capacityAmount = error.GetErrorType() == CoreErrors::REQUEST_TIMEOUT ? TIMEOUT_RETRY_COST : RETRY_COST; + ReleaseRetryQuota(capacityAmount); + } + } +}
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/SpecifiedRetryableErrorsRetryStrategy.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/SpecifiedRetryableErrorsRetryStrategy.cpp new file mode 100644 index 0000000000..ec4e373304 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/SpecifiedRetryableErrorsRetryStrategy.cpp @@ -0,0 +1,28 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/client/SpecifiedRetryableErrorsRetryStrategy.h> + +#include <aws/core/client/AWSError.h> + +using namespace Aws; +using namespace Aws::Client; + +bool SpecifiedRetryableErrorsRetryStrategy::ShouldRetry(const AWSError<CoreErrors>& error, long attemptedRetries) const +{ + if (attemptedRetries >= m_maxRetries) + { + return false; + } + for (const auto& err: m_specifiedRetryableErrors) + { + if (error.GetExceptionName() == err) + { + return true; + } + } + + return error.ShouldRetry(); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSProfileConfigLoader.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSProfileConfigLoader.cpp new file mode 100644 index 0000000000..9ec2e54f55 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSProfileConfigLoader.cpp @@ -0,0 +1,540 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/config/AWSProfileConfigLoader.h> +#include <aws/core/internal/AWSHttpResourceClient.h> +#include <aws/core/auth/AWSCredentialsProvider.h> +#include <aws/core/utils/memory/stl/AWSList.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/json/JsonSerializer.h> +#include <fstream> + +namespace Aws +{ + namespace Config + { + using namespace Aws::Utils; + using namespace Aws::Auth; + + static const char* const CONFIG_LOADER_TAG = "Aws::Config::AWSProfileConfigLoader"; + #ifdef _MSC_VER + // VS2015 compiler's bug, warning s_CoreErrorsMapper: symbol will be dynamically initialized (implementation limitation) + AWS_SUPPRESS_WARNING(4592, + static Aws::UniquePtr<ConfigAndCredentialsCacheManager> s_configManager(nullptr); + ) + #else + static Aws::UniquePtr<ConfigAndCredentialsCacheManager> s_configManager(nullptr); + #endif + + static const char CONFIG_CREDENTIALS_CACHE_MANAGER_TAG[] = "ConfigAndCredentialsCacheManager"; + + bool AWSProfileConfigLoader::Load() + { + if(LoadInternal()) + { + AWS_LOGSTREAM_INFO(CONFIG_LOADER_TAG, "Successfully reloaded configuration."); + m_lastLoadTime = DateTime::Now(); + AWS_LOGSTREAM_TRACE(CONFIG_LOADER_TAG, "reloaded config at " + << m_lastLoadTime.ToGmtString(DateFormat::ISO_8601)); + return true; + } + + AWS_LOGSTREAM_INFO(CONFIG_LOADER_TAG, "Failed to reload configuration."); + return false; + } + + bool AWSProfileConfigLoader::PersistProfiles(const Aws::Map<Aws::String, Profile>& profiles) + { + if(PersistInternal(profiles)) + { + AWS_LOGSTREAM_INFO(CONFIG_LOADER_TAG, "Successfully persisted configuration."); + m_profiles = profiles; + m_lastLoadTime = DateTime::Now(); + AWS_LOGSTREAM_TRACE(CONFIG_LOADER_TAG, "persisted config at " + << m_lastLoadTime.ToGmtString(DateFormat::ISO_8601)); + return true; + } + + AWS_LOGSTREAM_WARN(CONFIG_LOADER_TAG, "Failed to persist configuration."); + return false; + } + + static const char REGION_KEY[] = "region"; + static const char ACCESS_KEY_ID_KEY[] = "aws_access_key_id"; + static const char SECRET_KEY_KEY[] = "aws_secret_access_key"; + static const char SESSION_TOKEN_KEY[] = "aws_session_token"; + static const char ROLE_ARN_KEY[] = "role_arn"; + static const char EXTERNAL_ID_KEY[] = "external_id"; + static const char CREDENTIAL_PROCESS_COMMAND[] = "credential_process"; + static const char SOURCE_PROFILE_KEY[] = "source_profile"; + static const char PROFILE_PREFIX[] = "profile "; + static const char EQ = '='; + static const char LEFT_BRACKET = '['; + static const char RIGHT_BRACKET = ']'; + static const char PARSER_TAG[] = "Aws::Config::ConfigFileProfileFSM"; + + class ConfigFileProfileFSM + { + public: + ConfigFileProfileFSM() : m_parserState(START) {} + + const Aws::Map<String, Profile>& GetProfiles() const { return m_foundProfiles; } + + void ParseStream(Aws::IStream& stream) + { + static const size_t ASSUME_EMPTY_LEN = 3; + + Aws::String line; + while(std::getline(stream, line) && m_parserState != FAILURE) + { + if (line.empty() || line.length() < ASSUME_EMPTY_LEN) + { + continue; + } + + auto openPos = line.find(LEFT_BRACKET); + auto closePos = line.find(RIGHT_BRACKET); + + switch(m_parserState) + { + + case START: + if(openPos != std::string::npos && closePos != std::string::npos) + { + FlushProfileAndReset(line, openPos, closePos); + m_parserState = PROFILE_FOUND; + } + break; + + //fallthrough here is intentional to reduce duplicate logic + case PROFILE_KEY_VALUE_FOUND: + if(openPos != std::string::npos && closePos != std::string::npos) + { + m_parserState = PROFILE_FOUND; + FlushProfileAndReset(line, openPos, closePos); + break; + } + // fall through + case PROFILE_FOUND: + { + auto equalsPos = line.find(EQ); + if (equalsPos != std::string::npos) + { + auto key = line.substr(0, equalsPos); + auto value = line.substr(equalsPos + 1); + m_profileKeyValuePairs[StringUtils::Trim(key.c_str())] = + StringUtils::Trim(value.c_str()); + m_parserState = PROFILE_KEY_VALUE_FOUND; + } + + break; + } + default: + m_parserState = FAILURE; + break; + } + } + + FlushProfileAndReset(line, std::string::npos, std::string::npos); + } + + private: + + void FlushProfileAndReset(Aws::String& line, size_t openPos, size_t closePos) + { + if(!m_currentWorkingProfile.empty() && !m_profileKeyValuePairs.empty()) + { + Profile profile; + profile.SetName(m_currentWorkingProfile); + + auto regionIter = m_profileKeyValuePairs.find(REGION_KEY); + if (regionIter != m_profileKeyValuePairs.end()) + { + AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found region " << regionIter->second); + profile.SetRegion(regionIter->second); + } + + auto accessKeyIdIter = m_profileKeyValuePairs.find(ACCESS_KEY_ID_KEY); + Aws::String accessKey, secretKey, sessionToken; + if (accessKeyIdIter != m_profileKeyValuePairs.end()) + { + accessKey = accessKeyIdIter->second; + AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found access key " << accessKey); + + auto secretAccessKeyIter = m_profileKeyValuePairs.find(SECRET_KEY_KEY); + auto sessionTokenIter = m_profileKeyValuePairs.find(SESSION_TOKEN_KEY); + if (secretAccessKeyIter != m_profileKeyValuePairs.end()) + { + secretKey = secretAccessKeyIter->second; + } + else + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "No secret access key found even though an access key was specified. This will cause all signed AWS calls to fail."); + } + + if (sessionTokenIter != m_profileKeyValuePairs.end()) + { + sessionToken = sessionTokenIter->second; + } + + profile.SetCredentials(Aws::Auth::AWSCredentials(accessKey, secretKey, sessionToken)); + } + + auto assumeRoleArnIter = m_profileKeyValuePairs.find(ROLE_ARN_KEY); + if (assumeRoleArnIter != m_profileKeyValuePairs.end()) + { + AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found role arn " << assumeRoleArnIter->second); + profile.SetRoleArn(assumeRoleArnIter->second); + } + + auto externalIdIter = m_profileKeyValuePairs.find(EXTERNAL_ID_KEY); + if (externalIdIter != m_profileKeyValuePairs.end()) + { + AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found external id " << externalIdIter->second); + profile.SetExternalId(externalIdIter->second); + } + + auto sourceProfileIter = m_profileKeyValuePairs.find(SOURCE_PROFILE_KEY); + if (sourceProfileIter != m_profileKeyValuePairs.end()) + { + AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found source profile " << sourceProfileIter->second); + profile.SetSourceProfile(sourceProfileIter->second); + } + + auto credentialProcessIter = m_profileKeyValuePairs.find(CREDENTIAL_PROCESS_COMMAND); + if (credentialProcessIter != m_profileKeyValuePairs.end()) + { + AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found credential process " << credentialProcessIter->second); + profile.SetCredentialProcess(credentialProcessIter->second); + } + profile.SetAllKeyValPairs(m_profileKeyValuePairs); + + m_foundProfiles[profile.GetName()] = std::move(profile); + m_currentWorkingProfile.clear(); + m_profileKeyValuePairs.clear(); + } + + if(!line.empty() && openPos != std::string::npos && closePos != std::string::npos) + { + m_currentWorkingProfile = StringUtils::Trim(line.substr(openPos + 1, closePos - openPos - 1).c_str()); + StringUtils::Replace(m_currentWorkingProfile, PROFILE_PREFIX, ""); + AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found profile " << m_currentWorkingProfile); + } + } + + enum State + { + START = 0, + PROFILE_FOUND, + PROFILE_KEY_VALUE_FOUND, + FAILURE + }; + + Aws::String m_currentWorkingProfile; + Aws::Map<String, String> m_profileKeyValuePairs; + State m_parserState; + Aws::Map<String, Profile> m_foundProfiles; + }; + + static const char* const CONFIG_FILE_LOADER = "Aws::Config::AWSConfigFileProfileConfigLoader"; + + AWSConfigFileProfileConfigLoader::AWSConfigFileProfileConfigLoader(const Aws::String& fileName, bool useProfilePrefix) : + m_fileName(fileName), m_useProfilePrefix(useProfilePrefix) + { + AWS_LOGSTREAM_INFO(CONFIG_FILE_LOADER, "Initializing config loader against fileName " + << fileName << " and using profilePrefix = " << useProfilePrefix); + } + + bool AWSConfigFileProfileConfigLoader::LoadInternal() + { + m_profiles.clear(); + + Aws::IFStream inputFile(m_fileName.c_str()); + if(inputFile) + { + ConfigFileProfileFSM parser; + parser.ParseStream(inputFile); + m_profiles = parser.GetProfiles(); + return m_profiles.size() > 0; + } + + AWS_LOGSTREAM_INFO(CONFIG_FILE_LOADER, "Unable to open config file " << m_fileName << " for reading."); + + return false; + } + + bool AWSConfigFileProfileConfigLoader::PersistInternal(const Aws::Map<Aws::String, Profile>& profiles) + { + Aws::OFStream outputFile(m_fileName.c_str(), std::ios_base::out | std::ios_base::trunc); + if(outputFile) + { + for(auto& profile : profiles) + { + Aws::String prefix = m_useProfilePrefix ? PROFILE_PREFIX : ""; + + AWS_LOGSTREAM_DEBUG(CONFIG_FILE_LOADER, "Writing profile " << profile.first << " to disk."); + + outputFile << LEFT_BRACKET << prefix << profile.second.GetName() << RIGHT_BRACKET << std::endl; + const Aws::Auth::AWSCredentials& credentials = profile.second.GetCredentials(); + outputFile << ACCESS_KEY_ID_KEY << EQ << credentials.GetAWSAccessKeyId() << std::endl; + outputFile << SECRET_KEY_KEY << EQ << credentials.GetAWSSecretKey() << std::endl; + + if(!credentials.GetSessionToken().empty()) + { + outputFile << SESSION_TOKEN_KEY << EQ << credentials.GetSessionToken() << std::endl; + } + + if(!profile.second.GetRegion().empty()) + { + outputFile << REGION_KEY << EQ << profile.second.GetRegion() << std::endl; + } + + if(!profile.second.GetRoleArn().empty()) + { + outputFile << ROLE_ARN_KEY << EQ << profile.second.GetRoleArn() << std::endl; + } + + if(!profile.second.GetSourceProfile().empty()) + { + outputFile << SOURCE_PROFILE_KEY << EQ << profile.second.GetSourceProfile() << std::endl; + } + + outputFile << std::endl; + } + + AWS_LOGSTREAM_INFO(CONFIG_FILE_LOADER, "Profiles written to config file " << m_fileName); + + return true; + } + + AWS_LOGSTREAM_WARN(CONFIG_FILE_LOADER, "Unable to open config file " << m_fileName << " for writing."); + + return false; + } + + static const char* const EC2_INSTANCE_PROFILE_LOG_TAG = "Aws::Config::EC2InstanceProfileConfigLoader"; + + EC2InstanceProfileConfigLoader::EC2InstanceProfileConfigLoader(const std::shared_ptr<Aws::Internal::EC2MetadataClient>& client) + : m_ec2metadataClient(client == nullptr ? Aws::MakeShared<Aws::Internal::EC2MetadataClient>(EC2_INSTANCE_PROFILE_LOG_TAG) : client) + { + } + + bool EC2InstanceProfileConfigLoader::LoadInternal() + { + auto credentialsStr = m_ec2metadataClient->GetDefaultCredentialsSecurely(); + if(credentialsStr.empty()) return false; + + Json::JsonValue credentialsDoc(credentialsStr); + if (!credentialsDoc.WasParseSuccessful()) + { + AWS_LOGSTREAM_ERROR(EC2_INSTANCE_PROFILE_LOG_TAG, + "Failed to parse output from EC2MetadataService."); + return false; + } + const char* accessKeyId = "AccessKeyId"; + const char* secretAccessKey = "SecretAccessKey"; + Aws::String accessKey, secretKey, token; + + auto credentialsView = credentialsDoc.View(); + accessKey = credentialsView.GetString(accessKeyId); + AWS_LOGSTREAM_INFO(EC2_INSTANCE_PROFILE_LOG_TAG, + "Successfully pulled credentials from metadata service with access key " << accessKey); + + secretKey = credentialsView.GetString(secretAccessKey); + token = credentialsView.GetString("Token"); + + auto region = m_ec2metadataClient->GetCurrentRegion(); + + Profile profile; + profile.SetCredentials(AWSCredentials(accessKey, secretKey, token)); + profile.SetRegion(region); + profile.SetName(INSTANCE_PROFILE_KEY); + + m_profiles[INSTANCE_PROFILE_KEY] = profile; + + return true; + } + + ConfigAndCredentialsCacheManager::ConfigAndCredentialsCacheManager() : + m_credentialsFileLoader(Aws::Auth::ProfileConfigFileAWSCredentialsProvider::GetCredentialsProfileFilename()), + m_configFileLoader(Aws::Auth::GetConfigProfileFilename(), true/*use profile prefix*/) + { + ReloadCredentialsFile(); + ReloadConfigFile(); + } + + void ConfigAndCredentialsCacheManager::ReloadConfigFile() + { + Aws::Utils::Threading::WriterLockGuard guard(m_configLock); + m_configFileLoader.SetFileName(Aws::Auth::GetConfigProfileFilename()); + m_configFileLoader.Load(); + } + + void ConfigAndCredentialsCacheManager::ReloadCredentialsFile() + { + Aws::Utils::Threading::WriterLockGuard guard(m_credentialsLock); + m_credentialsFileLoader.SetFileName(Aws::Auth::ProfileConfigFileAWSCredentialsProvider::GetCredentialsProfileFilename()); + m_credentialsFileLoader.Load(); + } + + bool ConfigAndCredentialsCacheManager::HasConfigProfile(const Aws::String& profileName) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); + return (m_configFileLoader.GetProfiles().count(profileName) == 1); + } + + Aws::Config::Profile ConfigAndCredentialsCacheManager::GetConfigProfile(const Aws::String& profileName) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); + const auto& profiles = m_configFileLoader.GetProfiles(); + const auto &iter = profiles.find(profileName); + if (iter == profiles.end()) + { + return {}; + } + return iter->second; + } + + Aws::Map<Aws::String, Aws::Config::Profile> ConfigAndCredentialsCacheManager::GetConfigProfiles() const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); + return m_configFileLoader.GetProfiles(); + } + + Aws::String ConfigAndCredentialsCacheManager::GetConfig(const Aws::String& profileName, const Aws::String& key) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); + const auto& profiles = m_configFileLoader.GetProfiles(); + const auto &iter = profiles.find(profileName); + if (iter == profiles.end()) + { + return {}; + } + return iter->second.GetValue(key); + } + + bool ConfigAndCredentialsCacheManager::HasCredentialsProfile(const Aws::String& profileName) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); + return (m_credentialsFileLoader.GetProfiles().count(profileName) == 1); + } + + Aws::Config::Profile ConfigAndCredentialsCacheManager::GetCredentialsProfile(const Aws::String& profileName) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); + const auto &profiles = m_credentialsFileLoader.GetProfiles(); + const auto &iter = profiles.find(profileName); + if (iter == profiles.end()) + { + return {}; + } + return iter->second; + } + + Aws::Map<Aws::String, Aws::Config::Profile> ConfigAndCredentialsCacheManager::GetCredentialsProfiles() const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); + return m_credentialsFileLoader.GetProfiles(); + } + + Aws::Auth::AWSCredentials ConfigAndCredentialsCacheManager::GetCredentials(const Aws::String& profileName) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); + const auto& profiles = m_credentialsFileLoader.GetProfiles(); + const auto &iter = profiles.find(profileName); + if (iter == profiles.end()) + { + return {}; + } + return iter->second.GetCredentials(); + } + + void InitConfigAndCredentialsCacheManager() + { + if (s_configManager) + { + return; + } + s_configManager = Aws::MakeUnique<ConfigAndCredentialsCacheManager>(CONFIG_CREDENTIALS_CACHE_MANAGER_TAG); + } + + void CleanupConfigAndCredentialsCacheManager() + { + if (!s_configManager) + { + return; + } + s_configManager = nullptr; + } + + void ReloadCachedConfigFile() + { + assert(s_configManager); + s_configManager->ReloadConfigFile(); + } + + void ReloadCachedCredentialsFile() + { + assert(s_configManager); + s_configManager->ReloadCredentialsFile(); + } + + bool HasCachedConfigProfile(const Aws::String& profileName) + { + assert(s_configManager); + return s_configManager->HasConfigProfile(profileName); + } + + Aws::Config::Profile GetCachedConfigProfile(const Aws::String& profileName) + { + assert(s_configManager); + return s_configManager->GetConfigProfile(profileName); + } + + Aws::Map<Aws::String, Aws::Config::Profile> GetCachedConfigProfiles() + { + assert(s_configManager); + return s_configManager->GetConfigProfiles(); + } + + Aws::String GetCachedConfigValue(const Aws::String &profileName, const Aws::String &key) + { + assert(s_configManager); + return s_configManager->GetConfig(profileName, key); + } + + Aws::String GetCachedConfigValue(const Aws::String &key) + { + assert(s_configManager); + return s_configManager->GetConfig(Aws::Auth::GetConfigProfileName(), key); + } + + bool HasCachedCredentialsProfile(const Aws::String& profileName) + { + assert(s_configManager); + return s_configManager->HasCredentialsProfile(profileName); + } + + Aws::Config::Profile GetCachedCredentialsProfile(const Aws::String &profileName) + { + assert(s_configManager); + return s_configManager->GetCredentialsProfile(profileName); + } + + Aws::Map<Aws::String, Aws::Config::Profile> GetCachedCredentialsProfiles() + { + assert(s_configManager); + return s_configManager->GetCredentialsProfiles(); + } + + Aws::Auth::AWSCredentials GetCachedCredentials(const Aws::String &profileName) + { + assert(s_configManager); + return s_configManager->GetCredentials(profileName); + } + } // Config namespace +} // Aws namespace diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/cjson/cJSON.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/cjson/cJSON.cpp new file mode 100644 index 0000000000..2525976334 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/cjson/cJSON.cpp @@ -0,0 +1,2983 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +/* disable warnings about old C89 functions in MSVC */ +#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) +#define _CRT_SECURE_NO_DEPRECATE +#endif + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif +#if defined(_MSC_VER) +#pragma warning (push) +/* disable warning about single line comments in system headers */ +#pragma warning (disable : 4001) +#endif + +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <stdlib.h> +#include <limits.h> +#include <ctype.h> + +#ifdef ENABLE_LOCALES +#include <locale.h> +#endif + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif + +#include <aws/core/external/cjson/cJSON.h> + +/* define our own boolean type */ +// #define true ((cJSON_bool)1) +// #define false ((cJSON_bool)0) + +typedef struct { + const unsigned char *json; + size_t position; +} error; +static error global_error = { NULL, 0 }; + +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) +{ + return (const char*) (global_error.json + global_error.position); +} + +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { + if (!cJSON_IsString(item)) { + return NULL; + } + + return item->valuestring; +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 7) + #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#endif + +CJSON_PUBLIC(const char*) cJSON_Version(void) +{ + static char version[15]; + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + + return version; +} + +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) +{ + if ((string1 == NULL) || (string2 == NULL)) + { + return 1; + } + + if (string1 == string2) + { + return 0; + } + + for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) + { + if (*string1 == '\0') + { + return 0; + } + } + + return tolower(*string1) - tolower(*string2); +} + +typedef struct internal_hooks +{ + void *(*allocate)(size_t size); + void (*deallocate)(void *pointer); + void *(*reallocate)(void *pointer, size_t size); +} internal_hooks; + +#if defined(_MSC_VER) +/* work around MSVC error C2322: '...' address of dillimport '...' is not static */ +static void *internal_malloc(size_t size) +{ + return malloc(size); +} +static void internal_free(void *pointer) +{ + free(pointer); +} +static void *internal_realloc(void *pointer, size_t size) +{ + return realloc(pointer, size); +} +#else +#define internal_malloc malloc +#define internal_free free +#define internal_realloc realloc +#endif + +static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; + +static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if (string == NULL) + { + return NULL; + } + + length = strlen((const char*)string) + sizeof(""); + copy = (unsigned char*)hooks->allocate(length); + if (copy == NULL) + { + return NULL; + } + memcpy(copy, string, length); + + return copy; +} + +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (hooks == NULL) + { + /* Reset hooks */ + global_hooks.allocate = malloc; + global_hooks.deallocate = free; + global_hooks.reallocate = realloc; + return; + } + + global_hooks.allocate = malloc; + if (hooks->malloc_fn != NULL) + { + global_hooks.allocate = hooks->malloc_fn; + } + + global_hooks.deallocate = free; + if (hooks->free_fn != NULL) + { + global_hooks.deallocate = hooks->free_fn; + } + + /* use realloc only if both free and malloc are used */ + global_hooks.reallocate = NULL; + if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) + { + global_hooks.reallocate = realloc; + } +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(const internal_hooks * const hooks) +{ + cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); + if (node) + { + memset(node, '\0', sizeof(cJSON)); + } + + return node; +} + +/* Delete a cJSON structure. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) +{ + cJSON *next = NULL; + while (item != NULL) + { + next = item->next; + if (!(item->type & cJSON_IsReference) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) + { + global_hooks.deallocate(item->valuestring); + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + global_hooks.deallocate(item->string); + } + global_hooks.deallocate(item); + item = next; + } +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) +{ +#ifdef ENABLE_LOCALES + struct lconv *lconv = localeconv(); + return (unsigned char) lconv->decimal_point[0]; +#else + return '.'; +#endif +} + +typedef struct +{ + const unsigned char *content; + size_t length; + size_t offset; + size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ + internal_hooks hooks; +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + bool isInteger = true; + size_t i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) + { + switch (buffer_at_offset(input_buffer)[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + isInteger = false; + break; + + case '.': + number_c_string[i] = decimal_point; + isInteger = false; + break; + + default: + goto loop_end; + } + } +loop_end: + number_c_string[i] = '\0'; + + number = strtod((const char*)number_c_string, (char**)&after_end); + if (number_c_string == after_end) + { + return false; /* parse_error */ + } + + item->valuedouble = number; + // For integer which is out of the range of [INT_MIN, INT_MAX], it may lose precision if we cast it to double. + // Instead, we keep the integer literal as a string. + if (isInteger && (number > INT_MAX || number < INT_MIN)) + { + item->valuestring = (char*)cJSON_strdup(number_c_string, &global_hooks); + } + + /* use saturation in case of overflow */ + if (number >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (number <= INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)number; + } + + item->type = cJSON_Number; + + input_buffer->offset += (size_t)(after_end - number_c_string); + return true; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) + { + object->valueint = INT_MAX; + } + else if (number <= INT_MIN) + { + object->valueint = INT_MIN; + } + else + { + object->valueint = (int)number; + } + + return object->valuedouble = number; +} + +typedef struct +{ + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char* ensure(printbuffer * const p, size_t needed) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) + { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) + { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) + { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) + { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) + { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) + { + newsize = INT_MAX; + } + else + { + return NULL; + } + } + else + { + newsize = needed * 2; + } + + if (p->hooks.reallocate != NULL) + { + /* reallocate with realloc if available */ + newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); + if (newbuffer == NULL) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } + else + { + /* otherwise reallocate manually */ + newbuffer = (unsigned char*)p->hooks.allocate(newsize); + if (!newbuffer) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + if (newbuffer) + { + memcpy(newbuffer, p->buffer, p->offset + 1); + } + p->hooks.deallocate(p->buffer); + } + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer * const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) + { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char*)buffer_pointer); +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26]; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test; + + if (output_buffer == NULL) + { + return false; + } + + /* For integer which is out of the range of [INT_MIN, INT_MAX], valuestring is an integer literal. */ + if (item->valuestring) + { + length = sprintf((char*)number_buffer, "%s", item->valuestring); + } + /* This checks for NaN and Infinity */ + else if ((d * 0) != 0) + { + length = sprintf((char*)number_buffer, "null"); + } + else + { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char*)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d)) + { + /* If not, print with 17 decimal places of precision */ + length = sprintf((char*)number_buffer, "%1.17g", d); + } + } + + /* sprintf failed or buffer overrun occurred */ + if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) + { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); + if (output_pointer == NULL) + { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((size_t)length); i++) + { + if (number_buffer[i] == decimal_point) + { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (size_t)length; + + return true; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4(const unsigned char * const input) +{ + unsigned int h = 0; + size_t i = 0; + + for (i = 0; i < 4; i++) + { + /* parse digit */ + if ((input[i] >= '0') && (input[i] <= '9')) + { + h += (unsigned int) input[i] - '0'; + } + else if ((input[i] >= 'A') && (input[i] <= 'F')) + { + h += (unsigned int) 10 + input[i] - 'A'; + } + else if ((input[i] >= 'a') && (input[i] <= 'f')) + { + h += (unsigned int) 10 + input[i] - 'a'; + } + else /* invalid */ + { + return 0; + } + + if (i < 3) + { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 + * A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ((input_end - first_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4(first_sequence + 2); + + /* check that the code is valid */ + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) + { + goto fail; + } + + /* UTF16 surrogate pair */ + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) + { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ((input_end - second_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) + { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4(second_sequence + 2); + /* check that the code is valid */ + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) + { + /* invalid second half of the surrogate pair */ + goto fail; + } + + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); + } + else + { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint < 0x80) + { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } + else if (codepoint < 0x800) + { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } + else if (codepoint < 0x10000) + { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } + else if (codepoint <= 0x10FFFF) + { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } + else + { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) + { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); + codepoint >>= 6; + } + /* encode first byte */ + if (utf8_length > 1) + { + (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } + else + { + (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } + + *output_pointer += utf8_length; + + return sequence_length; + +fail: + return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') + { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + size_t allocation_length = 0; + size_t skipped_bytes = 0; + while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) + { + /* is escape sequence */ + if (input_end[0] == '\\') + { + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) + { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) + { + goto fail; /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); + if (output == NULL) + { + goto fail; /* allocation failure */ + } + } + + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) + { + if (*input_pointer != '\\') + { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else + { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) + { + goto fail; + } + + switch (input_pointer[1]) + { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) + { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = cJSON_String; + item->valuestring = (char*)output; + + input_buffer->offset = (size_t) (input_end - input_buffer->content); + input_buffer->offset++; + + return true; + +fail: + if (output != NULL) + { + input_buffer->hooks.deallocate(output); + } + + if (input_pointer != NULL) + { + input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } + + return false; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if (output_buffer == NULL) + { + return false; + } + + /* empty string */ + if (input == NULL) + { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "\"\""); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) + { + switch (*input_pointer) + { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) + { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (size_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) + { + return false; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) + { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) + { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) + { + /* normal character, copy */ + *output_pointer = *input_pointer; + } + else + { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) + { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char*)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) +{ + return print_string_ptr((unsigned char*)item->valuestring, p); +} + +/* Predeclare these prototypes. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) + { + return NULL; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) + { + buffer->offset++; + } + + if (buffer->offset == buffer->length) + { + buffer->offset--; + } + + return buffer; +} + +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) + { + return NULL; + } + + if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) + { + buffer->offset += 3; + } + + return buffer; +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if (value == NULL) + { + goto fail; + } + + buffer.content = (const unsigned char*)value; + buffer.length = strlen((const char*)value) + sizeof(""); + buffer.offset = 0; + buffer.hooks = global_hooks; + + item = cJSON_New_Item(&global_hooks); + if (item == NULL) /* memory fail */ + { + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) + { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) + { + buffer_skip_whitespace(&buffer); + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') + { + goto fail; + } + } + if (return_parse_end) + { + *return_parse_end = (const char*)buffer_at_offset(&buffer); + } + + return item; + +fail: + if (item != NULL) + { + cJSON_Delete(item); + } + + if (value != NULL) + { + error local_error; + local_error.json = (const unsigned char*)value; + local_error.position = 0; + + if (buffer.offset < buffer.length) + { + local_error.position = buffer.offset; + } + else if (buffer.length > 0) + { + local_error.position = buffer.length - 1; + } + + if (return_parse_end != NULL) + { + *return_parse_end = (const char*)local_error.json + local_error.position; + } + + global_error = local_error; + } + + return NULL; +} + +/* Default options for cJSON_Parse */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) +{ + return cJSON_ParseWithOpts(value, 0, 0); +} + +#define cjson_min(a, b) ((a < b) ? a : b) + +static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) +{ + static const size_t default_buffer_size = 256; + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); + buffer->length = default_buffer_size; + buffer->format = format; + buffer->hooks = *hooks; + if (buffer->buffer == NULL) + { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) + { + goto fail; + } + update_offset(buffer); + + /* check if reallocate is available */ + if (hooks->reallocate != NULL) + { + printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); + if (printed == NULL) { + goto fail; + } + buffer->buffer = NULL; + } + else /* otherwise copy the JSON over to a new buffer */ + { + printed = (unsigned char*) hooks->allocate(buffer->offset + 1); + if (printed == NULL) + { + goto fail; + } + memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate(buffer->buffer); + } + + return printed; + +fail: + if (buffer->buffer != NULL) + { + hooks->deallocate(buffer->buffer); + } + + if (printed != NULL) + { + hooks->deallocate(printed); + } + + return NULL; +} + +/* Render a cJSON item/entity/structure to text. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) +{ + return (char*)print(item, true, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) +{ + return (char*)print(item, false, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if (prebuffer < 0) + { + return NULL; + } + + p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); + if (!p.buffer) + { + return NULL; + } + + p.length = (size_t)prebuffer; + p.offset = 0; + p.noalloc = false; + p.format = fmt; + p.hooks = global_hooks; + + if (!print_value(item, &p)) + { + global_hooks.deallocate(p.buffer); + return NULL; + } + + return (char*)p.buffer; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if ((len < 0) || (buf == NULL)) + { + return false; + } + + p.buffer = (unsigned char*)buf; + p.length = (size_t)len; + p.offset = 0; + p.noalloc = true; + p.format = fmt; + p.hooks = global_hooks; + + return print_value(item, &p); +} + +/* Parser core - when encountering text, process appropriately. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) +{ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) + { + item->type = cJSON_NULL; + input_buffer->offset += 4; + return true; + } + /* false */ + if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) + { + item->type = cJSON_False; + input_buffer->offset += 5; + return true; + } + /* true */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) + { + item->type = cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return true; + } + /* string */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) + { + return parse_string(item, input_buffer); + } + /* number */ + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) + { + return parse_number(item, input_buffer); + } + /* array */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) + { + return parse_array(item, input_buffer); + } + /* object */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) + { + return parse_object(item, input_buffer); + } + + return false; +} + +/* Render a value to text. */ +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) + { + return false; + } + + switch ((item->type) & 0xFF) + { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "null"); + return true; + + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "false"); + return true; + + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "true"); + return true; + + case cJSON_Number: + return print_number(item, output_buffer); + + case cJSON_Raw: + { + size_t raw_length = 0; + if (item->valuestring == NULL) + { + return false; + } + + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) + { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } + + case cJSON_String: + return print_string(item, output_buffer); + + case cJSON_Array: + return print_array(item, output_buffer); + + case cJSON_Object: + return print_object(item, output_buffer); + + default: + return false; + } +} + +/* Build an array from input text. */ +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') + { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) + { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') + { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an array to text */ +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_element = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) + { + if (!print_value(current_element, output_buffer)) + { + return false; + } + update_offset(output_buffer); + if (current_element->next) + { + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ','; + if(output_buffer->format) + { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Build an object from the text. */ +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) + { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) + { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_string(current_item, input_buffer)) + { + goto fail; /* failed to parse name */ + } + buffer_skip_whitespace(input_buffer); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) + { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) + { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Object; + item->child = head; + + input_buffer->offset++; + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an object to text. */ +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_item = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output: */ + length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) + { + if (output_buffer->format) + { + size_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) + { + return false; + } + for (i = 0; i < output_buffer->depth; i++) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ':'; + if (output_buffer->format) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = (size_t) ((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + if (current_item->next) + { + *output_pointer++ = ','; + } + + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) + { + return false; + } + if (output_buffer->format) + { + size_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) + { + *output_pointer++ = '\t'; + } + } + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Get Array size/item / object item. */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) +{ + cJSON *child = NULL; + size_t size = 0; + + if (array == NULL) + { + return 0; + } + + child = array->child; + + while(child != NULL) + { + size++; + child = child->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return (int)size; +} + +static cJSON* get_array_item(const cJSON *array, size_t index) +{ + cJSON *current_child = NULL; + + if (array == NULL) + { + return NULL; + } + + current_child = array->child; + while ((current_child != NULL) && (index > 0)) + { + index--; + current_child = current_child->next; + } + + return current_child; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) +{ + if (index < 0) + { + return NULL; + } + + return get_array_item(array, (size_t)index); +} + +static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (name == NULL)) + { + return NULL; + } + + current_element = object->child; + if (case_sensitive) + { + while ((current_element != NULL) && (strcmp(name, current_element->string) != 0)) + { + current_element = current_element->next; + } + } + else + { + while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) + { + current_element = current_element->next; + } + } + + return current_element; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, false); +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) +{ + return cJSON_GetObjectItem(object, string) ? 1 : 0; +} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev, cJSON *item) +{ + prev->next = item; + item->prev = prev; +} + +/* Utility for handling references. */ +static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) +{ + cJSON *reference = NULL; + if (item == NULL) + { + return NULL; + } + + reference = cJSON_New_Item(hooks); + if (reference == NULL) + { + return NULL; + } + + memcpy(reference, item, sizeof(cJSON)); + reference->string = NULL; + reference->type |= cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; +} + +static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) +{ + cJSON *child = NULL; + + if ((item == NULL) || (array == NULL)) + { + return false; + } + + child = array->child; + + if (child == NULL) + { + /* list is empty, start new one */ + array->child = item; + } + else + { + /* append to the end */ + while (child->next) + { + child = child->next; + } + suffix_object(child, item); + } + + return true; +} + +/* Add item to array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + add_item_to_array(array, item); +} + +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic push +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif +/* helper function to cast away const */ +static void* cast_away_const(const void* string) +{ + return (void*)string; +} +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif + + +static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) +{ + char *new_key = NULL; + int new_type = cJSON_Invalid; + + if ((object == NULL) || (string == NULL) || (item == NULL)) + { + return false; + } + + if (constant_key) + { + new_key = (char*)cast_away_const(string); + new_type = item->type | cJSON_StringIsConst; + } + else + { + new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + if (new_key == NULL) + { + return false; + } + + new_type = item->type & ~cJSON_StringIsConst; + } + + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + hooks->deallocate(item->string); + } + + item->string = new_key; + item->type = new_type; + + return add_item_to_array(object, item); +} + +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, false); +} + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, true); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +{ + if (array == NULL) + { + return; + } + + add_item_to_array(array, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +{ + if ((object == NULL) || (string == NULL)) + { + return; + } + + add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) +{ + cJSON *null = cJSON_CreateNull(); + if (add_item_to_object(object, name, null, &global_hooks, false)) + { + return null; + } + + cJSON_Delete(null); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) +{ + cJSON *true_item = cJSON_CreateTrue(); + if (add_item_to_object(object, name, true_item, &global_hooks, false)) + { + return true_item; + } + + cJSON_Delete(true_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) +{ + cJSON *false_item = cJSON_CreateFalse(); + if (add_item_to_object(object, name, false_item, &global_hooks, false)) + { + return false_item; + } + + cJSON_Delete(false_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) +{ + cJSON *bool_item = cJSON_CreateBool(boolean); + if (add_item_to_object(object, name, bool_item, &global_hooks, false)) + { + return bool_item; + } + + cJSON_Delete(bool_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) +{ + cJSON *number_item = cJSON_CreateNumber(number); + if (add_item_to_object(object, name, number_item, &global_hooks, false)) + { + return number_item; + } + + cJSON_Delete(number_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) +{ + cJSON *string_item = cJSON_CreateString(string); + if (add_item_to_object(object, name, string_item, &global_hooks, false)) + { + return string_item; + } + + cJSON_Delete(string_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) +{ + cJSON *raw_item = cJSON_CreateRaw(raw); + if (add_item_to_object(object, name, raw_item, &global_hooks, false)) + { + return raw_item; + } + + cJSON_Delete(raw_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) +{ + cJSON *object_item = cJSON_CreateObject(); + if (add_item_to_object(object, name, object_item, &global_hooks, false)) + { + return object_item; + } + + cJSON_Delete(object_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) +{ + cJSON *array = cJSON_CreateArray(); + if (add_item_to_object(object, name, array, &global_hooks, false)) + { + return array; + } + + cJSON_Delete(array); + return NULL; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) +{ + if ((parent == NULL) || (item == NULL)) + { + return NULL; + } + + if (item->prev != NULL) + { + /* not the first element */ + item->prev->next = item->next; + } + if (item->next != NULL) + { + /* not the last element */ + item->next->prev = item->prev; + } + + if (item == parent->child) + { + /* first element */ + parent->child = item->next; + } + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) +{ + if (which < 0) + { + return NULL; + } + + return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) +{ + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItem(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); +} + +/* Replace array/object items with new ones. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +{ + cJSON *after_inserted = NULL; + + if (which < 0) + { + return; + } + + after_inserted = get_array_item(array, (size_t)which); + if (after_inserted == NULL) + { + add_item_to_array(array, newitem); + return; + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + if (after_inserted == array->child) + { + array->child = newitem; + } + else + { + newitem->prev->next = newitem; + } +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) +{ + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + { + return false; + } + + if (replacement == item) + { + return true; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if (replacement->next != NULL) + { + replacement->next->prev = replacement; + } + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + if (parent->child == item) + { + parent->child = replacement; + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +{ + if (which < 0) + { + return; + } + + cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); +} + +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) +{ + if ((replacement == NULL) || (string == NULL)) + { + return false; + } + + /* replace the name in the replacement */ + if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) + { + cJSON_free(replacement->string); + } + replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + replacement->type &= ~cJSON_StringIsConst; + + cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, false); +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, true); +} + +/* Create basic types: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_NULL; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_True; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = b ? cJSON_True : cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (num <= INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)num; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateInt64(long long num) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Number; + item->valuedouble = static_cast<double>(num); + + // For integer which is out of the range of [INT_MIN, INT_MAX], it may lose precision if we cast it to double. + // Instead, we keep the integer literal as a string. + if (num > INT_MAX || num < INT_MIN) + { + char buf[21]; + sprintf(buf, "%lld", num); + item->valuestring = (char*)cJSON_strdup((const unsigned char*)buf, &global_hooks); + } + + /* use saturation in case of overflow */ + if (num >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (num <= INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)num; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_String; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) + { + item->type = cJSON_String | cJSON_IsReference; + item->valuestring = (char*)cast_away_const(string); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Object | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Array | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Raw; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type=cJSON_Array; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Object; + } + + return item; +} + +/* Create Arrays: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber((double)numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0;a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (strings == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateString(strings[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p,n); + } + p = n; + } + + return a; +} + +/* Duplication */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +{ + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; + + /* Bail on bad ptr */ + if (!item) + { + goto fail; + } + /* Create new item */ + newitem = cJSON_New_Item(&global_hooks); + if (!newitem) + { + goto fail; + } + /* Copy over all vars */ + newitem->type = item->type & (~cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) + { + newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); + if (!newitem->valuestring) + { + goto fail; + } + } + if (item->string) + { + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + if (!newitem->string) + { + goto fail; + } + } + /* If non-recursive, then we're done! */ + if (!recurse) + { + return newitem; + } + /* Walk the ->next chain for the child. */ + child = item->child; + while (child != NULL) + { + newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) + { + goto fail; + } + if (next != NULL) + { + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } + else + { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + child = child->next; + } + + return newitem; + +fail: + if (newitem != NULL) + { + cJSON_Delete(newitem); + } + + return NULL; +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + unsigned char *into = (unsigned char*)json; + + if (json == NULL) + { + return; + } + + while (*json) + { + if (*json == ' ') + { + json++; + } + else if (*json == '\t') + { + /* Whitespace characters. */ + json++; + } + else if (*json == '\r') + { + json++; + } + else if (*json=='\n') + { + json++; + } + else if ((*json == '/') && (json[1] == '/')) + { + /* double-slash comments, to end of line. */ + while (*json && (*json != '\n')) + { + json++; + } + } + else if ((*json == '/') && (json[1] == '*')) + { + /* multiline comments. */ + while (*json && !((*json == '*') && (json[1] == '/'))) + { + json++; + } + json += 2; + } + else if (*json == '\"') + { + /* string literals, which are \" sensitive. */ + *into++ = (unsigned char)*json++; + while (*json && (*json != '\"')) + { + if (*json == '\\') + { + *into++ = (unsigned char)*json++; + } + *into++ = (unsigned char)*json++; + } + *into++ = (unsigned char)*json++; + } + else + { + /* All other characters. */ + *into++ = (unsigned char)*json++; + } + } + + /* and null-terminate. */ + *into = '\0'; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Invalid; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + + +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) +{ + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + { + return false; + } + + /* check if type is valid */ + switch (a->type & 0xFF) + { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; + } + + /* identical objects are equal */ + if (a == b) + { + return true; + } + + switch (a->type & 0xFF) + { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + return true; + + case cJSON_Number: + if (a->valuedouble == b->valuedouble) + { + return true; + } + return false; + + case cJSON_String: + case cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) + { + return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) + { + return true; + } + + return false; + + case cJSON_Array: + { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) + { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return false; + } + + return true; + } + + case cJSON_Object: + { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + cJSON_ArrayForEach(a_element, a) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) + { + return false; + } + + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + } + + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) + { + return false; + } + + if (!cJSON_Compare(b_element, a_element, case_sensitive)) + { + return false; + } + } + + return true; + } + + default: + return false; + } +} + +CJSON_PUBLIC(void *) cJSON_malloc(size_t size) +{ + return global_hooks.allocate(size); +} + +CJSON_PUBLIC(void) cJSON_free(void *object) +{ + global_hooks.deallocate(object); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/tinyxml2/tinyxml2.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/tinyxml2/tinyxml2.cpp new file mode 100644 index 0000000000..ebe0fd9eec --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/tinyxml2/tinyxml2.cpp @@ -0,0 +1,2802 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +/* +This file has been modified from its original version by Amazon: + (1) Memory management operations use aws memory management api + (2) #includes all use <> +*/ + +#include <aws/core/external/tinyxml2/tinyxml2.h> + +#include <new> // yes, this one new style header, is in the Android SDK. +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +# include <stddef.h> +# include <stdarg.h> +#else +# include <cstddef> +# include <cstdarg> +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) + // Microsoft Visual Studio, version 2005 and higher. Not WinCE. + /*int _snprintf_s( + char *buffer, + size_t sizeOfBuffer, + size_t count, + const char *format [, + argument] ... + );*/ + static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) + { + va_list va; + va_start( va, format ); + int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + va_end( va ); + return result; + } + + static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va ) + { + int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + return result; + } + + #define TIXML_VSCPRINTF _vscprintf + #define TIXML_SSCANF sscanf_s +#elif defined _MSC_VER + // Microsoft Visual Studio 2003 and earlier or WinCE + #define TIXML_SNPRINTF _snprintf + #define TIXML_VSNPRINTF _vsnprintf + #define TIXML_SSCANF sscanf + #if (_MSC_VER < 1400 ) && (!defined WINCE) + // Microsoft Visual Studio 2003 and not WinCE. + #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have. + #else + // Microsoft Visual Studio 2003 and earlier or WinCE. + static inline int TIXML_VSCPRINTF( const char* format, va_list va ) + { + int len = 512; + for (;;) { + len = len*2; + char* str = Aws::NewArray<char>(len, ALLOCATION_TAG); + const int required = _vsnprintf(str, len, format, va); + Aws::DeleteArray(str); + if ( required != -1 ) { + TIXMLASSERT( required >= 0 ); + len = required; + break; + } + } + TIXMLASSERT( len >= 0 ); + return len; + } + #endif +#else + // GCC version 3 and higher + //#warning( "Using sn* functions." ) + #define TIXML_SNPRINTF snprintf + #define TIXML_VSNPRINTF vsnprintf + static inline int TIXML_VSCPRINTF( const char* format, va_list va ) + { + int len = vsnprintf( 0, 0, format, va ); + TIXMLASSERT( len >= 0 ); + return len; + } + #define TIXML_SSCANF sscanf +#endif + + +static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF +static const char LF = LINE_FEED; +static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out +static const char CR = CARRIAGE_RETURN; +static const char SINGLE_QUOTE = '\''; +static const char DOUBLE_QUOTE = '\"'; + +// Bunch of unicode info at: +// http://www.unicode.org/faq/utf_bom.html +// ef bb bf (Microsoft "lead bytes") - designates UTF-8 + +static const unsigned char TIXML_UTF_LEAD_0 = 0xefU; +static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; +static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + +namespace Aws +{ +namespace External +{ +namespace tinyxml2 +{ + +struct Entity { + const char* pattern; + int length; + char value; +}; + +static const int NUM_ENTITIES = 5; +static const Entity entities[NUM_ENTITIES] = { + { "quot", 4, DOUBLE_QUOTE }, + { "amp", 3, '&' }, + { "apos", 4, SINGLE_QUOTE }, + { "lt", 2, '<' }, + { "gt", 2, '>' } +}; + + +StrPair::~StrPair() +{ + Reset(); +} + + +void StrPair::TransferTo( StrPair* other ) +{ + if ( this == other ) { + return; + } + // This in effect implements the assignment operator by "moving" + // ownership (as in auto_ptr). + + TIXMLASSERT( other != 0 ); + TIXMLASSERT( other->_flags == 0 ); + TIXMLASSERT( other->_start == 0 ); + TIXMLASSERT( other->_end == 0 ); + + other->Reset(); + + other->_flags = _flags; + other->_start = _start; + other->_end = _end; + + _flags = 0; + _start = 0; + _end = 0; +} + + +void StrPair::Reset() +{ + if ( _flags & NEEDS_DELETE ) { + Aws::DeleteArray(_start); + } + _flags = 0; + _start = 0; + _end = 0; +} + + +void StrPair::SetStr( const char* str, int flags ) +{ + TIXMLASSERT( str ); + Reset(); + size_t len = strlen( str ); + TIXMLASSERT( _start == 0 ); + _start = Aws::NewArray<char>(len+1, ALLOCATION_TAG); + memcpy( _start, str, len+1 ); + _end = _start + len; + _flags = flags | NEEDS_DELETE; +} + + +char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr ) +{ + TIXMLASSERT( p ); + TIXMLASSERT( endTag && *endTag ); + TIXMLASSERT(curLineNumPtr); + + char* start = p; + char endChar = *endTag; + size_t length = strlen( endTag ); + + // Inner loop of text parsing. + while ( *p ) { + if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) { + Set( start, p, strFlags ); + return p + length; + } else if (*p == '\n') { + ++(*curLineNumPtr); + } + ++p; + TIXMLASSERT( p ); + } + return 0; +} + + +char* StrPair::ParseName( char* p ) +{ + if ( !p || !(*p) ) { + return 0; + } + if ( !XMLUtil::IsNameStartChar( *p ) ) { + return 0; + } + + char* const start = p; + ++p; + while ( *p && XMLUtil::IsNameChar( *p ) ) { + ++p; + } + + Set( start, p, 0 ); + return p; +} + + +void StrPair::CollapseWhitespace() +{ + // Adjusting _start would cause undefined behavior on delete[] + TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 ); + // Trim leading space. + _start = XMLUtil::SkipWhiteSpace( _start, 0 ); + + if ( *_start ) { + const char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while( *p ) { + if ( XMLUtil::IsWhiteSpace( *p )) { + p = XMLUtil::SkipWhiteSpace( p, 0 ); + if ( *p == 0 ) { + break; // don't write to q; this trims the trailing space. + } + *q = ' '; + ++q; + } + *q = *p; + ++q; + ++p; + } + *q = 0; + } +} + + +const char* StrPair::GetStr() +{ + TIXMLASSERT( _start ); + TIXMLASSERT( _end ); + if ( _flags & NEEDS_FLUSH ) { + *_end = 0; + _flags ^= NEEDS_FLUSH; + + if ( _flags ) { + const char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while( p < _end ) { + if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) { + // CR-LF pair becomes LF + // CR alone becomes LF + // LF-CR becomes LF + if ( *(p+1) == LF ) { + p += 2; + } + else { + ++p; + } + *q = LF; + ++q; + } + else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { + if ( *(p+1) == CR ) { + p += 2; + } + else { + ++p; + } + *q = LF; + ++q; + } + else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { + // Entities handled by tinyXML2: + // - special entities in the entity table [in/out] + // - numeric character reference [in] + // 中 or 中 + + if ( *(p+1) == '#' ) { + const int buflen = 10; + char buf[buflen] = { 0 }; + int len = 0; + char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) ); + if ( adjusted == 0 ) { + *q = *p; + ++p; + ++q; + } + else { + TIXMLASSERT( 0 <= len && len <= buflen ); + TIXMLASSERT( q + len <= adjusted ); + p = adjusted; + memcpy( q, buf, len ); + q += len; + } + } + else { + bool entityFound = false; + for( int i = 0; i < NUM_ENTITIES; ++i ) { + const Entity& entity = entities[i]; + if ( strncmp( p + 1, entity.pattern, entity.length ) == 0 + && *( p + entity.length + 1 ) == ';' ) { + // Found an entity - convert. + *q = entity.value; + ++q; + p += entity.length + 2; + entityFound = true; + break; + } + } + if ( !entityFound ) { + // fixme: treat as error? + ++p; + ++q; + } + } + } + else { + *q = *p; + ++p; + ++q; + } + } + *q = 0; + } + // The loop below has plenty going on, and this + // is a less useful mode. Break it out. + if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) { + CollapseWhitespace(); + } + _flags = (_flags & NEEDS_DELETE); + } + TIXMLASSERT( _start ); + return _start; +} + + + + +// --------- XMLUtil ----------- // + +const char* XMLUtil::writeBoolTrue = "true"; +const char* XMLUtil::writeBoolFalse = "false"; + +void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse) +{ + static const char* defTrue = "true"; + static const char* defFalse = "false"; + + writeBoolTrue = (writeTrue) ? writeTrue : defTrue; + writeBoolFalse = (writeFalse) ? writeFalse : defFalse; +} + + +const char* XMLUtil::ReadBOM( const char* p, bool* bom ) +{ + TIXMLASSERT( p ); + TIXMLASSERT( bom ); + *bom = false; + const unsigned char* pu = reinterpret_cast<const unsigned char*>(p); + // Check for BOM: + if ( *(pu+0) == TIXML_UTF_LEAD_0 + && *(pu+1) == TIXML_UTF_LEAD_1 + && *(pu+2) == TIXML_UTF_LEAD_2 ) { + *bom = true; + p += 3; + } + TIXMLASSERT( p ); + return p; +} + + +void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) +{ + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) { + *length = 1; + } + else if ( input < 0x800 ) { + *length = 2; + } + else if ( input < 0x10000 ) { + *length = 3; + } + else if ( input < 0x200000 ) { + *length = 4; + } + else { + *length = 0; // This code won't convert this correctly anyway. + return; + } + + output += *length; + + // Scary scary fall throughs are annotated with carefully designed comments + // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc + switch (*length) { + case 4: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + //fall through + case 3: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + //fall through + case 2: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + //fall through + case 1: + --output; + *output = (char)(input | FIRST_BYTE_MARK[*length]); + break; + default: + TIXMLASSERT( false ); + } +} + + +const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length ) +{ + // Presume an entity, and pull it out. + *length = 0; + + if ( *(p+1) == '#' && *(p+2) ) { + unsigned long ucs = 0; + TIXMLASSERT( sizeof( ucs ) >= 4 ); + ptrdiff_t delta = 0; + unsigned mult = 1; + static const char SEMICOLON = ';'; + + if ( *(p+2) == 'x' ) { + // Hexadecimal. + const char* q = p+3; + if ( !(*q) ) { + return 0; + } + + q = strchr( q, SEMICOLON ); + + if ( !q ) { + return 0; + } + TIXMLASSERT( *q == SEMICOLON ); + + delta = q-p; + --q; + + while ( *q != 'x' ) { + unsigned int digit = 0; + + if ( *q >= '0' && *q <= '9' ) { + digit = *q - '0'; + } + else if ( *q >= 'a' && *q <= 'f' ) { + digit = *q - 'a' + 10; + } + else if ( *q >= 'A' && *q <= 'F' ) { + digit = *q - 'A' + 10; + } + else { + return 0; + } + TIXMLASSERT( digit < 16 ); + TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); + ucs += digitScaled; + TIXMLASSERT( mult <= UINT_MAX / 16 ); + mult *= 16; + --q; + } + } + else { + // Decimal. + const char* q = p+2; + if ( !(*q) ) { + return 0; + } + + q = strchr( q, SEMICOLON ); + + if ( !q ) { + return 0; + } + TIXMLASSERT( *q == SEMICOLON ); + + delta = q-p; + --q; + + while ( *q != '#' ) { + if ( *q >= '0' && *q <= '9' ) { + const unsigned int digit = *q - '0'; + TIXMLASSERT( digit < 10 ); + TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); + ucs += digitScaled; + } + else { + return 0; + } + TIXMLASSERT( mult <= UINT_MAX / 10 ); + mult *= 10; + --q; + } + } + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8( ucs, value, length ); + return p + delta + 1; + } + return p+1; +} + + +void XMLUtil::ToStr( int v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%d", v ); +} + + +void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%u", v ); +} + + +void XMLUtil::ToStr( bool v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse); +} + +/* + ToStr() of a number is a very tricky topic. + https://github.com/leethomason/tinyxml2/issues/106 +*/ +void XMLUtil::ToStr( float v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v ); +} + + +void XMLUtil::ToStr( double v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v ); +} + + +void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize) +{ + // horrible syntax trick to make the compiler happy about %lld + TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v); +} + + +bool XMLUtil::ToInt( const char* str, int* value ) +{ + if ( TIXML_SSCANF( str, "%d", value ) == 1 ) { + return true; + } + return false; +} + +bool XMLUtil::ToUnsigned( const char* str, unsigned *value ) +{ + if ( TIXML_SSCANF( str, "%u", value ) == 1 ) { + return true; + } + return false; +} + +bool XMLUtil::ToBool( const char* str, bool* value ) +{ + int ival = 0; + if ( ToInt( str, &ival )) { + *value = (ival==0) ? false : true; + return true; + } + if ( StringEqual( str, "true" ) ) { + *value = true; + return true; + } + else if ( StringEqual( str, "false" ) ) { + *value = false; + return true; + } + return false; +} + + +bool XMLUtil::ToFloat( const char* str, float* value ) +{ + if ( TIXML_SSCANF( str, "%f", value ) == 1 ) { + return true; + } + return false; +} + + +bool XMLUtil::ToDouble( const char* str, double* value ) +{ + if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) { + return true; + } + return false; +} + + +bool XMLUtil::ToInt64(const char* str, int64_t* value) +{ + long long v = 0; // horrible syntax trick to make the compiler happy about %lld + if (TIXML_SSCANF(str, "%lld", &v) == 1) { + *value = (int64_t)v; + return true; + } + return false; +} + + +char* XMLDocument::Identify( char* p, XMLNode** node ) +{ + TIXMLASSERT( node ); + TIXMLASSERT( p ); + char* const start = p; + int const startLine = _parseCurLineNum; + p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); + if( !*p ) { + *node = 0; + TIXMLASSERT( p ); + return p; + } + + // These strings define the matching patterns: + static const char* xmlHeader = { "<?" }; + static const char* commentHeader = { "<!--" }; + static const char* cdataHeader = { "<![CDATA[" }; + static const char* dtdHeader = { "<!" }; + static const char* elementHeader = { "<" }; // and a header for everything else; check last. + + static const int xmlHeaderLen = 2; + static const int commentHeaderLen = 4; + static const int cdataHeaderLen = 9; + static const int dtdHeaderLen = 2; + static const int elementHeaderLen = 1; + + TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool + TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool + XMLNode* returnNode = 0; + if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) { + returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool ); + returnNode->_parseLineNum = _parseCurLineNum; + p += xmlHeaderLen; + } + else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { + returnNode = CreateUnlinkedNode<XMLComment>( _commentPool ); + returnNode->_parseLineNum = _parseCurLineNum; + p += commentHeaderLen; + } + else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) { + XMLText* text = CreateUnlinkedNode<XMLText>( _textPool ); + returnNode = text; + returnNode->_parseLineNum = _parseCurLineNum; + p += cdataHeaderLen; + text->SetCData( true ); + } + else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { + returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool ); + returnNode->_parseLineNum = _parseCurLineNum; + p += dtdHeaderLen; + } + else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { + returnNode = CreateUnlinkedNode<XMLElement>( _elementPool ); + returnNode->_parseLineNum = _parseCurLineNum; + p += elementHeaderLen; + } + else { + returnNode = CreateUnlinkedNode<XMLText>( _textPool ); + returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character + p = start; // Back it up, all the text counts. + _parseCurLineNum = startLine; + } + + TIXMLASSERT( returnNode ); + TIXMLASSERT( p ); + *node = returnNode; + return p; +} + + +bool XMLDocument::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + if ( visitor->VisitEnter( *this ) ) { + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { + if ( !node->Accept( visitor ) ) { + break; + } + } + } + return visitor->VisitExit( *this ); +} + + +// --------- XMLNode ----------- // + +XMLNode::XMLNode( XMLDocument* doc ) : + _document( doc ), + _parent( 0 ), + _value(), + _parseLineNum( 0 ), + _firstChild( 0 ), _lastChild( 0 ), + _prev( 0 ), _next( 0 ), + _userData( 0 ), + _memPool( 0 ) +{ +} + + +XMLNode::~XMLNode() +{ + DeleteChildren(); + if ( _parent ) { + _parent->Unlink( this ); + } +} + +const char* XMLNode::Value() const +{ + // Edge case: XMLDocuments don't have a Value. Return null. + if ( this->ToDocument() ) + return 0; + return _value.GetStr(); +} + +void XMLNode::SetValue( const char* str, bool staticMem ) +{ + if ( staticMem ) { + _value.SetInternedStr( str ); + } + else { + _value.SetStr( str ); + } +} + +XMLNode* XMLNode::DeepClone(XMLDocument* target) const +{ + XMLNode* clone = this->ShallowClone(target); + if (!clone) return 0; + + for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) { + XMLNode* childClone = child->DeepClone(target); + TIXMLASSERT(childClone); + clone->InsertEndChild(childClone); + } + return clone; +} + +void XMLNode::DeleteChildren() +{ + while( _firstChild ) { + TIXMLASSERT( _lastChild ); + DeleteChild( _firstChild ); + } + _firstChild = _lastChild = 0; +} + + +void XMLNode::Unlink( XMLNode* child ) +{ + TIXMLASSERT( child ); + TIXMLASSERT( child->_document == _document ); + TIXMLASSERT( child->_parent == this ); + if ( child == _firstChild ) { + _firstChild = _firstChild->_next; + } + if ( child == _lastChild ) { + _lastChild = _lastChild->_prev; + } + + if ( child->_prev ) { + child->_prev->_next = child->_next; + } + if ( child->_next ) { + child->_next->_prev = child->_prev; + } + child->_next = 0; + child->_prev = 0; + child->_parent = 0; +} + + +void XMLNode::DeleteChild( XMLNode* node ) +{ + TIXMLASSERT( node ); + TIXMLASSERT( node->_document == _document ); + TIXMLASSERT( node->_parent == this ); + Unlink( node ); + TIXMLASSERT(node->_prev == 0); + TIXMLASSERT(node->_next == 0); + TIXMLASSERT(node->_parent == 0); + DeleteNode( node ); +} + + +XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + InsertChildPreamble( addThis ); + + if ( _lastChild ) { + TIXMLASSERT( _firstChild ); + TIXMLASSERT( _lastChild->_next == 0 ); + _lastChild->_next = addThis; + addThis->_prev = _lastChild; + _lastChild = addThis; + + addThis->_next = 0; + } + else { + TIXMLASSERT( _firstChild == 0 ); + _firstChild = _lastChild = addThis; + + addThis->_prev = 0; + addThis->_next = 0; + } + addThis->_parent = this; + return addThis; +} + + +XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + InsertChildPreamble( addThis ); + + if ( _firstChild ) { + TIXMLASSERT( _lastChild ); + TIXMLASSERT( _firstChild->_prev == 0 ); + + _firstChild->_prev = addThis; + addThis->_next = _firstChild; + _firstChild = addThis; + + addThis->_prev = 0; + } + else { + TIXMLASSERT( _lastChild == 0 ); + _firstChild = _lastChild = addThis; + + addThis->_prev = 0; + addThis->_next = 0; + } + addThis->_parent = this; + return addThis; +} + + +XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + + TIXMLASSERT( afterThis ); + + if ( afterThis->_parent != this ) { + TIXMLASSERT( false ); + return 0; + } + if ( afterThis == addThis ) { + // Current state: BeforeThis -> AddThis -> OneAfterAddThis + // Now AddThis must disappear from it's location and then + // reappear between BeforeThis and OneAfterAddThis. + // So just leave it where it is. + return addThis; + } + + if ( afterThis->_next == 0 ) { + // The last node or the only node. + return InsertEndChild( addThis ); + } + InsertChildPreamble( addThis ); + addThis->_prev = afterThis; + addThis->_next = afterThis->_next; + afterThis->_next->_prev = addThis; + afterThis->_next = addThis; + addThis->_parent = this; + return addThis; +} + + + + +const XMLElement* XMLNode::FirstChildElement( const char* name ) const +{ + for( const XMLNode* node = _firstChild; node; node = node->_next ) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { + return element; + } + } + return 0; +} + + +const XMLElement* XMLNode::LastChildElement( const char* name ) const +{ + for( const XMLNode* node = _lastChild; node; node = node->_prev ) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { + return element; + } + } + return 0; +} + + +const XMLElement* XMLNode::NextSiblingElement( const char* name ) const +{ + for( const XMLNode* node = _next; node; node = node->_next ) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { + return element; + } + } + return 0; +} + + +const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const +{ + for( const XMLNode* node = _prev; node; node = node->_prev ) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { + return element; + } + } + return 0; +} + + +char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) +{ + // This is a recursive method, but thinking about it "at the current level" + // it is a pretty simple flat list: + // <foo/> + // <!-- comment --> + // + // With a special case: + // <foo> + // </foo> + // <!-- comment --> + // + // Where the closing element (/foo) *must* be the next thing after the opening + // element, and the names must match. BUT the tricky bit is that the closing + // element will be read by the child. + // + // 'endTag' is the end tag for this node, it is returned by a call to a child. + // 'parentEnd' is the end tag for the parent, which is filled in and returned. + + while( p && *p ) { + XMLNode* node = 0; + + p = _document->Identify( p, &node ); + TIXMLASSERT( p ); + if ( node == 0 ) { + break; + } + + int initialLineNum = node->_parseLineNum; + + StrPair endTag; + p = node->ParseDeep( p, &endTag, curLineNumPtr ); + if ( !p ) { + DeleteNode( node ); + if ( !_document->Error() ) { + _document->SetError( XML_ERROR_PARSING, initialLineNum, 0); + } + break; + } + + XMLDeclaration* decl = node->ToDeclaration(); + if ( decl ) { + // Declarations are only allowed at document level + bool wellLocated = ( ToDocument() != 0 ); + if ( wellLocated ) { + // Multiple declarations are allowed but all declarations + // must occur before anything else + for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) { + if ( !existingNode->ToDeclaration() ) { + wellLocated = false; + break; + } + } + } + if ( !wellLocated ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value()); + DeleteNode( node ); + break; + } + } + + XMLElement* ele = node->ToElement(); + if ( ele ) { + // We read the end tag. Return it to the parent. + if ( ele->ClosingType() == XMLElement::CLOSING ) { + if ( parentEndTag ) { + ele->_value.TransferTo( parentEndTag ); + } + node->_memPool->SetTracked(); // created and then immediately deleted. + DeleteNode( node ); + return p; + } + + // Handle an end tag returned to this level. + // And handle a bunch of annoying errors. + bool mismatch = false; + if ( endTag.Empty() ) { + if ( ele->ClosingType() == XMLElement::OPEN ) { + mismatch = true; + } + } + else { + if ( ele->ClosingType() != XMLElement::OPEN ) { + mismatch = true; + } + else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) { + mismatch = true; + } + } + if ( mismatch ) { + _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name()); + DeleteNode( node ); + break; + } + } + InsertEndChild( node ); + } + return 0; +} + +/*static*/ void XMLNode::DeleteNode( XMLNode* node ) +{ + if ( node == 0 ) { + return; + } + TIXMLASSERT(node->_document); + if (!node->ToDocument()) { + node->_document->MarkInUse(node); + } + + MemPool* pool = node->_memPool; + node->~XMLNode(); + pool->Free( node ); +} + +void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const +{ + TIXMLASSERT( insertThis ); + TIXMLASSERT( insertThis->_document == _document ); + + if (insertThis->_parent) { + insertThis->_parent->Unlink( insertThis ); + } + else { + insertThis->_document->MarkInUse(insertThis); + insertThis->_memPool->SetTracked(); + } +} + +const XMLElement* XMLNode::ToElementWithName( const char* name ) const +{ + const XMLElement* element = this->ToElement(); + if ( element == 0 ) { + return 0; + } + if ( name == 0 ) { + return element; + } + if ( XMLUtil::StringEqual( element->Name(), name ) ) { + return element; + } + return 0; +} + +// --------- XMLText ---------- // +char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) +{ + if ( this->CData() ) { + p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 ); + } + return p; + } + else { + int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; + if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) { + flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING; + } + + p = _value.ParseText( p, "<", flags, curLineNumPtr ); + if ( p && *p ) { + return p-1; + } + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 ); + } + } + return 0; +} + + +XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern? + text->SetCData( this->CData() ); + return text; +} + + +bool XMLText::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLText* text = compare->ToText(); + return ( text && XMLUtil::StringEqual( text->Value(), Value() ) ); +} + + +bool XMLText::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + + +// --------- XMLComment ---------- // + +XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLComment::~XMLComment() +{ +} + + +char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) +{ + // Comment parses as text. + p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr ); + if ( p == 0 ) { + _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 ); + } + return p; +} + + +XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern? + return comment; +} + + +bool XMLComment::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLComment* comment = compare->ToComment(); + return ( comment && XMLUtil::StringEqual( comment->Value(), Value() )); +} + + +bool XMLComment::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + + +// --------- XMLDeclaration ---------- // + +XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLDeclaration::~XMLDeclaration() +{ + //printf( "~XMLDeclaration\n" ); +} + + +char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) +{ + // Declaration parses as text. + p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); + if ( p == 0 ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 ); + } + return p; +} + + +XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern? + return dec; +} + + +bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLDeclaration* declaration = compare->ToDeclaration(); + return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() )); +} + + + +bool XMLDeclaration::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + +// --------- XMLUnknown ---------- // + +XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLUnknown::~XMLUnknown() +{ +} + + +char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) +{ + // Unknown parses as text. + p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 ); + } + return p; +} + + +XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern? + return text; +} + + +bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLUnknown* unknown = compare->ToUnknown(); + return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() )); +} + + +bool XMLUnknown::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + +// --------- XMLAttribute ---------- // + +const char* XMLAttribute::Name() const +{ + return _name.GetStr(); +} + +const char* XMLAttribute::Value() const +{ + return _value.GetStr(); +} + +char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr ) +{ + // Parse using the name rules: bug fix, was using ParseText before + p = _name.ParseName( p ); + if ( !p || !*p ) { + return 0; + } + + // Skip white space before = + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); + if ( *p != '=' ) { + return 0; + } + + ++p; // move up to opening quote + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); + if ( *p != '\"' && *p != '\'' ) { + return 0; + } + + char endTag[2] = { *p, 0 }; + ++p; // move past opening quote + + p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr ); + return p; +} + + +void XMLAttribute::SetName( const char* n ) +{ + _name.SetStr( n ); +} + + +XMLError XMLAttribute::QueryIntValue( int* value ) const +{ + if ( XMLUtil::ToInt( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const +{ + if ( XMLUtil::ToUnsigned( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryInt64Value(int64_t* value) const +{ + if (XMLUtil::ToInt64(Value(), value)) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryBoolValue( bool* value ) const +{ + if ( XMLUtil::ToBool( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryFloatValue( float* value ) const +{ + if ( XMLUtil::ToFloat( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryDoubleValue( double* value ) const +{ + if ( XMLUtil::ToDouble( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +void XMLAttribute::SetAttribute( const char* v ) +{ + _value.SetStr( v ); +} + + +void XMLAttribute::SetAttribute( int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +void XMLAttribute::SetAttribute( unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +void XMLAttribute::SetAttribute(int64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + _value.SetStr(buf); +} + + + +void XMLAttribute::SetAttribute( bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + +void XMLAttribute::SetAttribute( double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + +void XMLAttribute::SetAttribute( float v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +// --------- XMLElement ---------- // +XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ), + _closingType( OPEN ), + _rootAttribute( 0 ) +{ +} + + +XMLElement::~XMLElement() +{ + while( _rootAttribute ) { + XMLAttribute* next = _rootAttribute->_next; + DeleteAttribute( _rootAttribute ); + _rootAttribute = next; + } +} + + +const XMLAttribute* XMLElement::FindAttribute( const char* name ) const +{ + for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) { + if ( XMLUtil::StringEqual( a->Name(), name ) ) { + return a; + } + } + return 0; +} + + +const char* XMLElement::Attribute( const char* name, const char* value ) const +{ + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return 0; + } + if ( !value || XMLUtil::StringEqual( a->Value(), value )) { + return a->Value(); + } + return 0; +} + +int XMLElement::IntAttribute(const char* name, int defaultValue) const +{ + int i = defaultValue; + QueryIntAttribute(name, &i); + return i; +} + +unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const +{ + unsigned i = defaultValue; + QueryUnsignedAttribute(name, &i); + return i; +} + +int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const +{ + int64_t i = defaultValue; + QueryInt64Attribute(name, &i); + return i; +} + +bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const +{ + bool b = defaultValue; + QueryBoolAttribute(name, &b); + return b; +} + +double XMLElement::DoubleAttribute(const char* name, double defaultValue) const +{ + double d = defaultValue; + QueryDoubleAttribute(name, &d); + return d; +} + +float XMLElement::FloatAttribute(const char* name, float defaultValue) const +{ + float f = defaultValue; + QueryFloatAttribute(name, &f); + return f; +} + +const char* XMLElement::GetText() const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + return FirstChild()->Value(); + } + return 0; +} + + +void XMLElement::SetText( const char* inText ) +{ + if ( FirstChild() && FirstChild()->ToText() ) + FirstChild()->SetValue( inText ); + else { + XMLText* theText = GetDocument()->NewText( inText ); + InsertFirstChild( theText ); + } +} + + +void XMLElement::SetText( int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText(int64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + SetText(buf); +} + + +void XMLElement::SetText( bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( float v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +XMLError XMLElement::QueryIntText( int* ival ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToInt( t, ival ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToUnsigned( t, uval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryInt64Text(int64_t* ival) const +{ + if (FirstChild() && FirstChild()->ToText()) { + const char* t = FirstChild()->Value(); + if (XMLUtil::ToInt64(t, ival)) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryBoolText( bool* bval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToBool( t, bval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryDoubleText( double* dval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToDouble( t, dval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryFloatText( float* fval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToFloat( t, fval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + +int XMLElement::IntText(int defaultValue) const +{ + int i = defaultValue; + QueryIntText(&i); + return i; +} + +unsigned XMLElement::UnsignedText(unsigned defaultValue) const +{ + unsigned i = defaultValue; + QueryUnsignedText(&i); + return i; +} + +int64_t XMLElement::Int64Text(int64_t defaultValue) const +{ + int64_t i = defaultValue; + QueryInt64Text(&i); + return i; +} + +bool XMLElement::BoolText(bool defaultValue) const +{ + bool b = defaultValue; + QueryBoolText(&b); + return b; +} + +double XMLElement::DoubleText(double defaultValue) const +{ + double d = defaultValue; + QueryDoubleText(&d); + return d; +} + +float XMLElement::FloatText(float defaultValue) const +{ + float f = defaultValue; + QueryFloatText(&f); + return f; +} + + +XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) +{ + XMLAttribute* last = 0; + XMLAttribute* attrib = 0; + for( attrib = _rootAttribute; + attrib; + last = attrib, attrib = attrib->_next ) { + if ( XMLUtil::StringEqual( attrib->Name(), name ) ) { + break; + } + } + if ( !attrib ) { + attrib = CreateAttribute(); + TIXMLASSERT( attrib ); + if ( last ) { + TIXMLASSERT( last->_next == 0 ); + last->_next = attrib; + } + else { + TIXMLASSERT( _rootAttribute == 0 ); + _rootAttribute = attrib; + } + attrib->SetName( name ); + } + return attrib; +} + + +void XMLElement::DeleteAttribute( const char* name ) +{ + XMLAttribute* prev = 0; + for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) { + if ( XMLUtil::StringEqual( name, a->Name() ) ) { + if ( prev ) { + prev->_next = a->_next; + } + else { + _rootAttribute = a->_next; + } + DeleteAttribute( a ); + break; + } + prev = a; + } +} + + +char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr ) +{ + XMLAttribute* prevAttribute = 0; + + // Read the attributes. + while( p ) { + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); + if ( !(*p) ) { + _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() ); + return 0; + } + + // attribute. + if (XMLUtil::IsNameStartChar( *p ) ) { + XMLAttribute* attrib = CreateAttribute(); + TIXMLASSERT( attrib ); + attrib->_parseLineNum = _document->_parseCurLineNum; + + int attrLineNum = attrib->_parseLineNum; + + p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr ); + if ( !p || Attribute( attrib->Name() ) ) { + DeleteAttribute( attrib ); + _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() ); + return 0; + } + // There is a minor bug here: if the attribute in the source xml + // document is duplicated, it will not be detected and the + // attribute will be doubly added. However, tracking the 'prevAttribute' + // avoids re-scanning the attribute list. Preferring performance for + // now, may reconsider in the future. + if ( prevAttribute ) { + TIXMLASSERT( prevAttribute->_next == 0 ); + prevAttribute->_next = attrib; + } + else { + TIXMLASSERT( _rootAttribute == 0 ); + _rootAttribute = attrib; + } + prevAttribute = attrib; + } + // end of the tag + else if ( *p == '>' ) { + ++p; + break; + } + // end of the tag + else if ( *p == '/' && *(p+1) == '>' ) { + _closingType = CLOSED; + return p+2; // done; sealed element. + } + else { + _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 ); + return 0; + } + } + return p; +} + +void XMLElement::DeleteAttribute( XMLAttribute* attribute ) +{ + if ( attribute == 0 ) { + return; + } + MemPool* pool = attribute->_memPool; + attribute->~XMLAttribute(); + pool->Free( attribute ); +} + +XMLAttribute* XMLElement::CreateAttribute() +{ + TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); + XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); + TIXMLASSERT( attrib ); + attrib->_memPool = &_document->_attributePool; + attrib->_memPool->SetTracked(); + return attrib; +} + +// +// <ele></ele> +// <ele>foo<b>bar</b></ele> +// +char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) +{ + // Read the element name. + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); + + // The closing element is the </element> form. It is + // parsed just like a regular element then deleted from + // the DOM. + if ( *p == '/' ) { + _closingType = CLOSING; + ++p; + } + + p = _value.ParseName( p ); + if ( _value.Empty() ) { + return 0; + } + + p = ParseAttributes( p, curLineNumPtr ); + if ( !p || !*p || _closingType != OPEN ) { + return p; + } + + p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr ); + return p; +} + + + +XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern? + for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) { + element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern? + } + return element; +} + + +bool XMLElement::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLElement* other = compare->ToElement(); + if ( other && XMLUtil::StringEqual( other->Name(), Name() )) { + + const XMLAttribute* a=FirstAttribute(); + const XMLAttribute* b=other->FirstAttribute(); + + while ( a && b ) { + if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) { + return false; + } + a = a->Next(); + b = b->Next(); + } + if ( a || b ) { + // different count + return false; + } + return true; + } + return false; +} + + +bool XMLElement::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + if ( visitor->VisitEnter( *this, _rootAttribute ) ) { + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { + if ( !node->Accept( visitor ) ) { + break; + } + } + } + return visitor->VisitExit( *this ); +} + + +// --------- XMLDocument ----------- // + +// Warning: List must match 'enum XMLError' +const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = { + "XML_SUCCESS", + "XML_NO_ATTRIBUTE", + "XML_WRONG_ATTRIBUTE_TYPE", + "XML_ERROR_FILE_NOT_FOUND", + "XML_ERROR_FILE_COULD_NOT_BE_OPENED", + "XML_ERROR_FILE_READ_ERROR", + "UNUSED_XML_ERROR_ELEMENT_MISMATCH", + "XML_ERROR_PARSING_ELEMENT", + "XML_ERROR_PARSING_ATTRIBUTE", + "UNUSED_XML_ERROR_IDENTIFYING_TAG", + "XML_ERROR_PARSING_TEXT", + "XML_ERROR_PARSING_CDATA", + "XML_ERROR_PARSING_COMMENT", + "XML_ERROR_PARSING_DECLARATION", + "XML_ERROR_PARSING_UNKNOWN", + "XML_ERROR_EMPTY_DOCUMENT", + "XML_ERROR_MISMATCHED_ELEMENT", + "XML_ERROR_PARSING", + "XML_CAN_NOT_CONVERT_TEXT", + "XML_NO_TEXT_NODE" +}; + + +XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) : + XMLNode( 0 ), + _writeBOM( false ), + _processEntities( processEntities ), + _errorID(XML_SUCCESS), + _whitespaceMode( whitespaceMode ), + _errorStr(), + _errorLineNum( 0 ), + _charBuffer( 0 ), + _parseCurLineNum( 0 ), + _unlinked(), + _elementPool(), + _attributePool(), + _textPool(), + _commentPool() +{ + // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+) + _document = this; +} + + +XMLDocument::~XMLDocument() +{ + Clear(); +} + + +void XMLDocument::MarkInUse(XMLNode* node) +{ + TIXMLASSERT(node); + TIXMLASSERT(node->_parent == 0); + + for (int i = 0; i < _unlinked.Size(); ++i) { + if (node == _unlinked[i]) { + _unlinked.SwapRemove(i); + break; + } + } +} + +void XMLDocument::Clear() +{ + DeleteChildren(); + while( _unlinked.Size()) { + DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete. + } + +#ifdef DEBUG + const bool hadError = Error(); +#endif + ClearError(); + + Aws::DeleteArray(_charBuffer); + _charBuffer = 0; + +#if 0 + _textPool.Trace( "text" ); + _elementPool.Trace( "element" ); + _commentPool.Trace( "comment" ); + _attributePool.Trace( "attribute" ); +#endif + +#ifdef DEBUG + if ( !hadError ) { + TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() ); + TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() ); + TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() ); + TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() ); + } +#endif +} + + +void XMLDocument::DeepCopy(XMLDocument* target) const +{ + TIXMLASSERT(target); + if (target == this) { + return; // technically success - a no-op. + } + + target->Clear(); + for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) { + target->InsertEndChild(node->DeepClone(target)); + } +} + +XMLElement* XMLDocument::NewElement( const char* name ) +{ + XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool ); + ele->SetName( name ); + return ele; +} + + +XMLComment* XMLDocument::NewComment( const char* str ) +{ + XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool ); + comment->SetValue( str ); + return comment; +} + + +XMLText* XMLDocument::NewText( const char* str ) +{ + XMLText* text = CreateUnlinkedNode<XMLText>( _textPool ); + text->SetValue( str ); + return text; +} + + +XMLDeclaration* XMLDocument::NewDeclaration( const char* str ) +{ + XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool ); + dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" ); + return dec; +} + + +XMLUnknown* XMLDocument::NewUnknown( const char* str ) +{ + XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool ); + unk->SetValue( str ); + return unk; +} + +static FILE* callfopen( const char* filepath, const char* mode ) +{ + TIXMLASSERT( filepath ); + TIXMLASSERT( mode ); +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) + FILE* fp = 0; + errno_t err = fopen_s( &fp, filepath, mode ); + if ( err ) { + return 0; + } +#else + FILE* fp = fopen( filepath, mode ); +#endif + return fp; +} + +void XMLDocument::DeleteNode( XMLNode* node ) { + TIXMLASSERT( node ); + TIXMLASSERT(node->_document == this ); + if (node->_parent) { + node->_parent->DeleteChild( node ); + } + else { + // Isn't in the tree. + // Use the parent delete. + // Also, we need to mark it tracked: we 'know' + // it was never used. + node->_memPool->SetTracked(); + // Call the static XMLNode version: + XMLNode::DeleteNode(node); + } +} + + +XMLError XMLDocument::LoadFile( const char* filename ) +{ + Clear(); + FILE* fp = callfopen( filename, "rb" ); + if ( !fp ) { + SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ? filename : "<null>"); + return _errorID; + } + LoadFile( fp ); + fclose( fp ); + return _errorID; +} + +// This is likely overengineered template art to have a check that unsigned long value incremented +// by one still fits into size_t. If size_t type is larger than unsigned long type +// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit +// -Wtype-limits warning. This piece makes the compiler select code with a check when a check +// is useful and code with no check when a check is redundant depending on how size_t and unsigned long +// types sizes relate to each other. +template +<bool = (sizeof(unsigned long) >= sizeof(size_t))> +struct LongFitsIntoSizeTMinusOne { + static bool Fits( unsigned long value ) + { + return value < (size_t)-1; + } +}; + +template <> +struct LongFitsIntoSizeTMinusOne<false> { + static bool Fits( unsigned long ) + { + return true; + } +}; + +XMLError XMLDocument::LoadFile( FILE* fp ) +{ + Clear(); + + fseek( fp, 0, SEEK_SET ); + if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + fseek( fp, 0, SEEK_END ); + const long filelength = ftell( fp ); + fseek( fp, 0, SEEK_SET ); + if ( filelength == -1L ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + TIXMLASSERT( filelength >= 0 ); + + if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) { + // Cannot handle files which won't fit in buffer together with null terminator + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + if ( filelength == 0 ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + + const size_t size = filelength; + TIXMLASSERT( _charBuffer == 0 ); + _charBuffer = Aws::NewArray <char>(size+1, ALLOCATION_TAG); + size_t read = fread( _charBuffer, 1, size, fp ); + if ( read != size ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + _charBuffer[size] = 0; + + Parse(); + return _errorID; +} + + +XMLError XMLDocument::SaveFile( const char* filename, bool compact ) +{ + FILE* fp = callfopen( filename, "w" ); + if ( !fp ) { + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ? filename : "<null>"); + return _errorID; + } + SaveFile(fp, compact); + fclose( fp ); + return _errorID; +} + + +XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) +{ + // Clear any error from the last save, otherwise it will get reported + // for *this* call. + ClearError(); + XMLPrinter stream( fp, compact ); + Print( &stream ); + return _errorID; +} + + +XMLError XMLDocument::Parse( const char* p, size_t len ) +{ + Clear(); + + if ( len == 0 || !p || !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + if ( len == (size_t)(-1) ) { + len = strlen( p ); + } + TIXMLASSERT( _charBuffer == 0 ); + _charBuffer = Aws::NewArray<char>(len+1, ALLOCATION_TAG); + memcpy( _charBuffer, p, len ); + _charBuffer[len] = 0; + + Parse(); + if ( Error() ) { + // clean up now essentially dangling memory. + // and the parse fail can put objects in the + // pools that are dead and inaccessible. + DeleteChildren(); + _elementPool.Clear(); + _attributePool.Clear(); + _textPool.Clear(); + _commentPool.Clear(); + } + return _errorID; +} + + +void XMLDocument::Print( XMLPrinter* streamer ) const +{ + if ( streamer ) { + Accept( streamer ); + } + else { + XMLPrinter stdoutStreamer( stdout ); + Accept( &stdoutStreamer ); + } +} + + +void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... ) +{ + TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT ); + _errorID = error; + _errorLineNum = lineNum; + _errorStr.Reset(); + + if (format) { + size_t BUFFER_SIZE = 1000; + char* buffer = Aws::NewArray<char>(BUFFER_SIZE, ALLOCATION_TAG); + TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d: ", ErrorIDToName(error), int(error), int(error), lineNum); + size_t len = strlen(buffer); + + va_list va; + va_start( va, format ); + TIXML_VSNPRINTF( buffer + len, BUFFER_SIZE - len, format, va ); + va_end( va ); + + _errorStr.SetStr(buffer); + Aws::DeleteArray(buffer); + } +} + + +/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID) +{ + TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT ); + const char* errorName = _errorNames[errorID]; + TIXMLASSERT( errorName && errorName[0] ); + return errorName; +} + +const char* XMLDocument::ErrorStr() const +{ + return _errorStr.Empty() ? "" : _errorStr.GetStr(); +} + + +void XMLDocument::PrintError() const +{ + printf("%s\n", ErrorStr()); +} + +const char* XMLDocument::ErrorName() const +{ + return ErrorIDToName(_errorID); +} + +void XMLDocument::Parse() +{ + TIXMLASSERT( NoChildren() ); // Clear() must have been called previously + TIXMLASSERT( _charBuffer ); + _parseCurLineNum = 1; + _parseLineNum = 1; + char* p = _charBuffer; + p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); + p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) ); + if ( !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return; + } + ParseDeep(p, 0, &_parseCurLineNum ); +} + +XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : + _elementJustOpened( false ), + _stack(), + _firstElement( true ), + _fp( file ), + _depth( depth ), + _textDepth( -1 ), + _processEntities( true ), + _compactMode( compact ), + _buffer() +{ + for( int i=0; i<ENTITY_RANGE; ++i ) { + _entityFlag[i] = false; + _restrictedEntityFlag[i] = false; + } + for( int i=0; i<NUM_ENTITIES; ++i ) { + const char entityValue = entities[i].value; + const unsigned char flagIndex = (unsigned char)entityValue; + TIXMLASSERT( flagIndex < ENTITY_RANGE ); + _entityFlag[flagIndex] = true; + } + _restrictedEntityFlag[(unsigned char)'&'] = true; + _restrictedEntityFlag[(unsigned char)'<'] = true; + _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice + _buffer.Push( 0 ); +} + + +void XMLPrinter::Print( const char* format, ... ) +{ + va_list va; + va_start( va, format ); + + if ( _fp ) { + vfprintf( _fp, format, va ); + } + else { + const int len = TIXML_VSCPRINTF( format, va ); + // Close out and re-start the va-args + va_end( va ); + TIXMLASSERT( len >= 0 ); + va_start( va, format ); + TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 ); + char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator. + TIXML_VSNPRINTF( p, len+1, format, va ); + } + va_end( va ); +} + + +void XMLPrinter::Write( const char* data, size_t size ) +{ + if ( _fp ) { + fwrite ( data , sizeof(char), size, _fp); + } + else { + char* p = _buffer.PushArr( static_cast<int>(size) ) - 1; // back up over the null terminator. + memcpy( p, data, size ); + p[size] = 0; + } +} + + +void XMLPrinter::Putc( char ch ) +{ + if ( _fp ) { + fputc ( ch, _fp); + } + else { + char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator. + p[0] = ch; + p[1] = 0; + } +} + + +void XMLPrinter::PrintSpace( int depth ) +{ + for( int i=0; i<depth; ++i ) { + Write( " " ); + } +} + + +void XMLPrinter::PrintString( const char* p, bool restricted ) +{ + // Look for runs of bytes between entities to print. + const char* q = p; + + if ( _processEntities ) { + const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag; + while ( *q ) { + TIXMLASSERT( p <= q ); + // Remember, char is sometimes signed. (How many times has that bitten me?) + if ( *q > 0 && *q < ENTITY_RANGE ) { + // Check for entities. If one is found, flush + // the stream up until the entity, write the + // entity, and keep looking. + if ( flag[(unsigned char)(*q)] ) { + while ( p < q ) { + const size_t delta = q - p; + const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta; + Write( p, toPrint ); + p += toPrint; + } + bool entityPatternPrinted = false; + for( int i=0; i<NUM_ENTITIES; ++i ) { + if ( entities[i].value == *q ) { + Putc( '&' ); + Write( entities[i].pattern, entities[i].length ); + Putc( ';' ); + entityPatternPrinted = true; + break; + } + } + if ( !entityPatternPrinted ) { + // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release + TIXMLASSERT( false ); + } + ++p; + } + } + ++q; + TIXMLASSERT( p <= q ); + } + } + // Flush the remaining string. This will be the entire + // string if an entity wasn't found. + TIXMLASSERT( p <= q ); + if ( !_processEntities || ( p < q ) ) { + const size_t delta = q - p; + const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta; + Write( p, toPrint ); + } +} + + +void XMLPrinter::PushHeader( bool writeBOM, bool writeDec ) +{ + if ( writeBOM ) { + static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 }; + Write( reinterpret_cast< const char* >( bom ) ); + } + if ( writeDec ) { + PushDeclaration( "xml version=\"1.0\"" ); + } +} + + +void XMLPrinter::OpenElement( const char* name, bool compactMode ) +{ + SealElementIfJustOpened(); + _stack.Push( name ); + + if ( _textDepth < 0 && !_firstElement && !compactMode ) { + Putc( '\n' ); + } + if ( !compactMode ) { + PrintSpace( _depth ); + } + + Write ( "<" ); + Write ( name ); + + _elementJustOpened = true; + _firstElement = false; + ++_depth; +} + + +void XMLPrinter::PushAttribute( const char* name, const char* value ) +{ + TIXMLASSERT( _elementJustOpened ); + Putc ( ' ' ); + Write( name ); + Write( "=\"" ); + PrintString( value, false ); + Putc ( '\"' ); +} + + +void XMLPrinter::PushAttribute( const char* name, int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute( const char* name, unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute(const char* name, int64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + PushAttribute(name, buf); +} + + +void XMLPrinter::PushAttribute( const char* name, bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute( const char* name, double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::CloseElement( bool compactMode ) +{ + --_depth; + const char* name = _stack.Pop(); + + if ( _elementJustOpened ) { + Write( "/>" ); + } + else { + if ( _textDepth < 0 && !compactMode) { + Putc( '\n' ); + PrintSpace( _depth ); + } + Write ( "</" ); + Write ( name ); + Write ( ">" ); + } + + if ( _textDepth == _depth ) { + _textDepth = -1; + } + if ( _depth == 0 && !compactMode) { + Putc( '\n' ); + } + _elementJustOpened = false; +} + + +void XMLPrinter::SealElementIfJustOpened() +{ + if ( !_elementJustOpened ) { + return; + } + _elementJustOpened = false; + Putc( '>' ); +} + + +void XMLPrinter::PushText( const char* text, bool cdata ) +{ + _textDepth = _depth-1; + + SealElementIfJustOpened(); + if ( cdata ) { + Write( "<![CDATA[" ); + Write( text ); + Write( "]]>" ); + } + else { + PrintString( text, true ); + } +} + +void XMLPrinter::PushText( int64_t value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + +void XMLPrinter::PushText( int value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( unsigned value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( bool value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( float value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( double value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushComment( const char* comment ) +{ + SealElementIfJustOpened(); + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Putc( '\n' ); + PrintSpace( _depth ); + } + _firstElement = false; + + Write( "<!--" ); + Write( comment ); + Write( "-->" ); +} + + +void XMLPrinter::PushDeclaration( const char* value ) +{ + SealElementIfJustOpened(); + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Putc( '\n' ); + PrintSpace( _depth ); + } + _firstElement = false; + + Write( "<?" ); + Write( value ); + Write( "?>" ); +} + + +void XMLPrinter::PushUnknown( const char* value ) +{ + SealElementIfJustOpened(); + if ( _textDepth < 0 && !_firstElement && !_compactMode) { + Putc( '\n' ); + PrintSpace( _depth ); + } + _firstElement = false; + + Write( "<!" ); + Write( value ); + Putc( '>' ); +} + + +bool XMLPrinter::VisitEnter( const XMLDocument& doc ) +{ + _processEntities = doc.ProcessEntities(); + if ( doc.HasBOM() ) { + PushHeader( true, false ); + } + return true; +} + + +bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) +{ + const XMLElement* parentElem = 0; + if ( element.Parent() ) { + parentElem = element.Parent()->ToElement(); + } + const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode; + OpenElement( element.Name(), compactMode ); + while ( attribute ) { + PushAttribute( attribute->Name(), attribute->Value() ); + attribute = attribute->Next(); + } + return true; +} + + +bool XMLPrinter::VisitExit( const XMLElement& element ) +{ + CloseElement( CompactMode(element) ); + return true; +} + + +bool XMLPrinter::Visit( const XMLText& text ) +{ + PushText( text.Value(), text.CData() ); + return true; +} + + +bool XMLPrinter::Visit( const XMLComment& comment ) +{ + PushComment( comment.Value() ); + return true; +} + +bool XMLPrinter::Visit( const XMLDeclaration& declaration ) +{ + PushDeclaration( declaration.Value() ); + return true; +} + + +bool XMLPrinter::Visit( const XMLUnknown& unknown ) +{ + PushUnknown( unknown.Value() ); + return true; +} + +} // namespace tinyxml2 +} // namespace External +} // namespace Aws
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpClient.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpClient.cpp new file mode 100644 index 0000000000..8542023393 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpClient.cpp @@ -0,0 +1,49 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/http/HttpClient.h> +#include <aws/core/http/HttpRequest.h> + +using namespace Aws; +using namespace Aws::Http; + +HttpClient::HttpClient() : + m_disableRequestProcessing( false ), + m_requestProcessingSignalLock(), + m_requestProcessingSignal() +{ +} + +void HttpClient::DisableRequestProcessing() +{ + m_disableRequestProcessing = true; + m_requestProcessingSignal.notify_all(); +} + +void HttpClient::EnableRequestProcessing() +{ + m_disableRequestProcessing = false; +} + +bool HttpClient::IsRequestProcessingEnabled() const +{ + return m_disableRequestProcessing.load() == false; +} + +void HttpClient::RetryRequestSleep(std::chrono::milliseconds sleepTime) +{ + std::unique_lock< std::mutex > signalLocker(m_requestProcessingSignalLock); + m_requestProcessingSignal.wait_for(signalLocker, sleepTime, [this](){ return m_disableRequestProcessing.load() == true; }); +} + +bool HttpClient::ContinueRequest(const Aws::Http::HttpRequest& request) const +{ + if (request.GetContinueRequestHandler()) + { + return request.GetContinueRequestHandler()(&request); + } + + return true; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpClientFactory.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpClientFactory.cpp new file mode 100644 index 0000000000..a556e39a5d --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpClientFactory.cpp @@ -0,0 +1,203 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/http/HttpClientFactory.h> + +#if ENABLE_CURL_CLIENT +#include <aws/core/http/curl/CurlHttpClient.h> +#include <signal.h> + +#elif ENABLE_WINDOWS_CLIENT +#include <aws/core/client/ClientConfiguration.h> +#if ENABLE_WINDOWS_IXML_HTTP_REQUEST_2_CLIENT +#error #include <aws/core/http/windows/IXmlHttpRequest2HttpClient.h> +#if BYPASS_DEFAULT_PROXY +#error #include <aws/core/http/windows/WinHttpSyncHttpClient.h> +#endif +#else +#error #include <aws/core/http/windows/WinINetSyncHttpClient.h> +#error #include <aws/core/http/windows/WinHttpSyncHttpClient.h> +#endif +#endif + +#include <aws/core/http/standard/StandardHttpRequest.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <cassert> + +using namespace Aws::Client; +using namespace Aws::Http; +using namespace Aws::Utils::Logging; + +namespace Aws +{ + namespace Http + { + static std::shared_ptr<HttpClientFactory>& GetHttpClientFactory() + { + static std::shared_ptr<HttpClientFactory> s_HttpClientFactory(nullptr); + return s_HttpClientFactory; + } + static bool s_InitCleanupCurlFlag(false); + static bool s_InstallSigPipeHandler(false); + + static const char* HTTP_CLIENT_FACTORY_ALLOCATION_TAG = "HttpClientFactory"; + +#if ENABLE_CURL_CLIENT && !defined(_WIN32) + static void LogAndSwallowHandler(int signal) + { + switch(signal) + { + case SIGPIPE: + AWS_LOGSTREAM_ERROR(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, "Received a SIGPIPE error"); + break; + default: + AWS_LOGSTREAM_ERROR(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, "Unhandled system SIGNAL error" << signal); + } + } +#endif + + class DefaultHttpClientFactory : public HttpClientFactory + { + std::shared_ptr<HttpClient> CreateHttpClient(const ClientConfiguration& clientConfiguration) const override + { + // Figure out whether the selected option is available but fail gracefully and return a default of some type if not + // Windows clients: Http and Inet are always options, Curl MIGHT be an option if USE_CURL_CLIENT is on, and http is "default" + // Other clients: Curl is your default +#if ENABLE_WINDOWS_CLIENT +#if ENABLE_WINDOWS_IXML_HTTP_REQUEST_2_CLIENT +#if BYPASS_DEFAULT_PROXY + switch (clientConfiguration.httpLibOverride) + { + case TransferLibType::WIN_HTTP_CLIENT: + AWS_LOGSTREAM_INFO(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, "Creating WinHTTP http client."); + return Aws::MakeShared<WinHttpSyncHttpClient>(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, clientConfiguration); + case TransferLibType::WIN_INET_CLIENT: + AWS_LOGSTREAM_WARN(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, "WinINet http client is not supported with the current build configuration."); + // fall-through + default: + AWS_LOGSTREAM_INFO(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, "Creating IXMLHttpRequest http client."); + return Aws::MakeShared<IXmlHttpRequest2HttpClient>(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, clientConfiguration); + } +#else + return Aws::MakeShared<IXmlHttpRequest2HttpClient>(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, clientConfiguration); +#endif // BYPASS_DEFAULT_PROXY +#else + switch (clientConfiguration.httpLibOverride) + { + case TransferLibType::WIN_INET_CLIENT: + return Aws::MakeShared<WinINetSyncHttpClient>(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, clientConfiguration); + + default: + return Aws::MakeShared<WinHttpSyncHttpClient>(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, clientConfiguration); + } +#endif // ENABLE_WINDOWS_IXML_HTTP_REQUEST_2_CLIENT +#elif ENABLE_CURL_CLIENT + return Aws::MakeShared<CurlHttpClient>(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, clientConfiguration); +#else + // When neither of these clients is enabled, gcc gives a warning (converted + // to error by -Werror) about the unused clientConfiguration parameter. We + // prevent that warning with AWS_UNREFERENCED_PARAM. + AWS_UNREFERENCED_PARAM(clientConfiguration); + AWS_LOGSTREAM_WARN(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, "SDK was built without an Http implementation, default http client factory can't create an Http client instance."); + return nullptr; +#endif + } + + std::shared_ptr<HttpRequest> CreateHttpRequest(const Aws::String &uri, HttpMethod method, + const Aws::IOStreamFactory &streamFactory) const override + { + return CreateHttpRequest(URI(uri), method, streamFactory); + } + + std::shared_ptr<HttpRequest> CreateHttpRequest(const URI& uri, HttpMethod method, const Aws::IOStreamFactory& streamFactory) const override + { + auto request = Aws::MakeShared<Standard::StandardHttpRequest>(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, uri, method); + request->SetResponseStreamFactory(streamFactory); + + return request; + } + + void InitStaticState() override + { +#if ENABLE_CURL_CLIENT + if(s_InitCleanupCurlFlag) + { + CurlHttpClient::InitGlobalState(); + } +#if !defined (_WIN32) + if(s_InstallSigPipeHandler) + { + ::signal(SIGPIPE, LogAndSwallowHandler); + } +#endif +#elif ENABLE_WINDOWS_IXML_HTTP_REQUEST_2_CLIENT + IXmlHttpRequest2HttpClient::InitCOM(); +#endif + } + + virtual void CleanupStaticState() override + { +#if ENABLE_CURL_CLIENT + if(s_InitCleanupCurlFlag) + { + CurlHttpClient::CleanupGlobalState(); + } +#endif + } + }; + + void SetInitCleanupCurlFlag(bool initCleanupFlag) + { + s_InitCleanupCurlFlag = initCleanupFlag; + } + + void SetInstallSigPipeHandlerFlag(bool install) + { + s_InstallSigPipeHandler = install; + } + + void InitHttp() + { + if(!GetHttpClientFactory()) + { + GetHttpClientFactory() = Aws::MakeShared<DefaultHttpClientFactory>(HTTP_CLIENT_FACTORY_ALLOCATION_TAG); + } + GetHttpClientFactory()->InitStaticState(); + } + + void CleanupHttp() + { + if(GetHttpClientFactory()) + { + GetHttpClientFactory()->CleanupStaticState(); + GetHttpClientFactory() = nullptr; + } + } + + void SetHttpClientFactory(const std::shared_ptr<HttpClientFactory>& factory) + { + CleanupHttp(); + GetHttpClientFactory() = factory; + } + + std::shared_ptr<HttpClient> CreateHttpClient(const Aws::Client::ClientConfiguration& clientConfiguration) + { + assert(GetHttpClientFactory()); + return GetHttpClientFactory()->CreateHttpClient(clientConfiguration); + } + + std::shared_ptr<HttpRequest> CreateHttpRequest(const Aws::String& uri, HttpMethod method, const Aws::IOStreamFactory& streamFactory) + { + assert(GetHttpClientFactory()); + return GetHttpClientFactory()->CreateHttpRequest(uri, method, streamFactory); + } + + std::shared_ptr<HttpRequest> CreateHttpRequest(const URI& uri, HttpMethod method, const Aws::IOStreamFactory& streamFactory) + { + assert(GetHttpClientFactory()); + return GetHttpClientFactory()->CreateHttpRequest(uri, method, streamFactory); + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpRequest.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpRequest.cpp new file mode 100644 index 0000000000..95cb626c22 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpRequest.cpp @@ -0,0 +1,40 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/http/HttpRequest.h> + +namespace Aws +{ +namespace Http +{ + +const char DATE_HEADER[] = "date"; +const char AWS_DATE_HEADER[] = "X-Amz-Date"; +const char AWS_SECURITY_TOKEN[] = "X-Amz-Security-Token"; +const char ACCEPT_HEADER[] = "accept"; +const char ACCEPT_CHAR_SET_HEADER[] = "accept-charset"; +const char ACCEPT_ENCODING_HEADER[] = "accept-encoding"; +const char AUTHORIZATION_HEADER[] = "authorization"; +const char AWS_AUTHORIZATION_HEADER[] = "authorization"; +const char COOKIE_HEADER[] = "cookie"; +const char CONTENT_LENGTH_HEADER[] = "content-length"; +const char CONTENT_TYPE_HEADER[] = "content-type"; +const char TRANSFER_ENCODING_HEADER[] = "transfer-encoding"; +const char USER_AGENT_HEADER[] = "user-agent"; +const char VIA_HEADER[] = "via"; +const char HOST_HEADER[] = "host"; +const char AMZ_TARGET_HEADER[] = "x-amz-target"; +const char X_AMZ_EXPIRES_HEADER[] = "X-Amz-Expires"; +const char CONTENT_MD5_HEADER[] = "content-md5"; +const char API_VERSION_HEADER[] = "x-amz-api-version"; +const char SDK_INVOCATION_ID_HEADER[] = "amz-sdk-invocation-id"; +const char SDK_REQUEST_HEADER[] = "amz-sdk-request"; +const char CHUNKED_VALUE[] = "chunked"; + +} // Http +} // Aws + + + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpTypes.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpTypes.cpp new file mode 100644 index 0000000000..4d313e52f3 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpTypes.cpp @@ -0,0 +1,42 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/http/HttpTypes.h> +#include <cassert> + +using namespace Aws::Http; + +namespace Aws +{ +namespace Http +{ + +namespace HttpMethodMapper +{ +const char* GetNameForHttpMethod(HttpMethod httpMethod) +{ + switch (httpMethod) + { + case HttpMethod::HTTP_GET: + return "GET"; + case HttpMethod::HTTP_POST: + return "POST"; + case HttpMethod::HTTP_DELETE: + return "DELETE"; + case HttpMethod::HTTP_PUT: + return "PUT"; + case HttpMethod::HTTP_HEAD: + return "HEAD"; + case HttpMethod::HTTP_PATCH: + return "PATCH"; + default: + assert(0); + return "GET"; + } +} + +} // namespace HttpMethodMapper +} // namespace Http +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/Scheme.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/Scheme.cpp new file mode 100644 index 0000000000..5dcea06aab --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/Scheme.cpp @@ -0,0 +1,54 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/http/Scheme.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <aws/core/utils/StringUtils.h> + +using namespace Aws::Http; +using namespace Aws::Utils; + +namespace Aws +{ +namespace Http +{ +namespace SchemeMapper +{ + + const char* ToString(Scheme scheme) + { + switch (scheme) + { + case Scheme::HTTP: + return "http"; + case Scheme::HTTPS: + return "https"; + default: + return "http"; + } + } + + Scheme FromString(const char* name) + { + Aws::String trimmedString = StringUtils::Trim(name); + Aws::String loweredTrimmedString = StringUtils::ToLower(trimmedString.c_str()); + + if (loweredTrimmedString == "http") + { + return Scheme::HTTP; + } + //this branch is technically unneeded, but it is here so we don't have a subtle bug + //creep in as we extend this enum. + else if (loweredTrimmedString == "https") + { + return Scheme::HTTPS; + } + + return Scheme::HTTPS; + } + +} // namespace SchemeMapper +} // namespace Http +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/URI.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/URI.cpp new file mode 100644 index 0000000000..a2239df54b --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/URI.cpp @@ -0,0 +1,510 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/http/URI.h> + +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> +#include <aws/core/utils/memory/stl/AWSSet.h> + +#include <cstdlib> +#include <cctype> +#include <cassert> +#include <algorithm> +#include <iomanip> + +using namespace Aws::Http; +using namespace Aws::Utils; + +namespace Aws +{ +namespace Http +{ + +const char* SEPARATOR = "://"; + +} // namespace Http +} // namespace Aws + +URI::URI() : m_scheme(Scheme::HTTP), m_port(HTTP_DEFAULT_PORT) +{ +} + +URI::URI(const Aws::String& uri) : m_scheme(Scheme::HTTP), m_port(HTTP_DEFAULT_PORT) +{ + ParseURIParts(uri); +} + +URI::URI(const char* uri) : m_scheme(Scheme::HTTP), m_port(HTTP_DEFAULT_PORT) +{ + ParseURIParts(uri); +} + +URI& URI::operator =(const Aws::String& uri) +{ + this->ParseURIParts(uri); + return *this; +} + +URI& URI::operator =(const char* uri) +{ + this->ParseURIParts(uri); + return *this; +} + +bool URI::operator ==(const URI& other) const +{ + return CompareURIParts(other); +} + +bool URI::operator ==(const Aws::String& other) const +{ + return CompareURIParts(other); +} + +bool URI::operator ==(const char* other) const +{ + return CompareURIParts(other); +} + +bool URI::operator !=(const URI& other) const +{ + return !(*this == other); +} + +bool URI::operator !=(const Aws::String& other) const +{ + return !(*this == other); +} + +bool URI::operator !=(const char* other) const +{ + return !(*this == other); +} + +void URI::SetScheme(Scheme value) +{ + assert(value == Scheme::HTTP || value == Scheme::HTTPS); + + if (value == Scheme::HTTP) + { + m_port = m_port == HTTPS_DEFAULT_PORT || m_port == 0 ? HTTP_DEFAULT_PORT : m_port; + m_scheme = value; + } + else if (value == Scheme::HTTPS) + { + m_port = m_port == HTTP_DEFAULT_PORT || m_port == 0 ? HTTPS_DEFAULT_PORT : m_port; + m_scheme = value; + } +} + +Aws::String URI::URLEncodePathRFC3986(const Aws::String& path) +{ + if(path.empty()) + { + return path; + } + + const Aws::Vector<Aws::String> pathParts = StringUtils::Split(path, '/'); + Aws::StringStream ss; + ss << std::hex << std::uppercase; + + // escape characters appearing in a URL path according to RFC 3986 + for (const auto& segment : pathParts) + { + ss << '/'; + for(unsigned char c : segment) // alnum results in UB if the value of c is not unsigned char & is not EOF + { + // §2.3 unreserved characters + if (StringUtils::IsAlnum(c)) + { + ss << c; + continue; + } + switch(c) + { + // §2.3 unreserved characters + case '-': case '_': case '.': case '~': + // The path section of the URL allow reserved characters to appear unescaped + // RFC 3986 §2.2 Reserved characters + // NOTE: this implementation does not accurately implement the RFC on purpose to accommodate for + // discrepancies in the implementations of URL encoding between AWS services for legacy reasons. + case '$': case '&': case ',': + case ':': case '=': case '@': + ss << c; + break; + default: + ss << '%' << std::setfill('0') << std::setw(2) << (int)((unsigned char)c) << std::setw(0); + } + } + } + + //if the last character was also a slash, then add that back here. + if (path.back() == '/') + { + ss << '/'; + } + + return ss.str(); +} + +Aws::String URI::URLEncodePath(const Aws::String& path) +{ + Aws::Vector<Aws::String> pathParts = StringUtils::Split(path, '/'); + Aws::StringStream ss; + + for (Aws::Vector<Aws::String>::iterator iter = pathParts.begin(); iter != pathParts.end(); ++iter) + { + ss << '/' << StringUtils::URLEncode(iter->c_str()); + } + + //if the last character was also a slash, then add that back here. + if (path.length() > 0 && path[path.length() - 1] == '/') + { + ss << '/'; + } + + if (path.length() > 0 && path[0] != '/') + { + return ss.str().substr(1); + } + else + { + return ss.str(); + } +} + +void URI::SetPath(const Aws::String& value) +{ + const Aws::Vector<Aws::String> pathParts = StringUtils::Split(value, '/'); + Aws::String path; + path.reserve(value.length() + 1/* in case we have to append slash before the path. */); + + for (const auto& segment : pathParts) + { + path.push_back('/'); + path.append(segment); + } + + if (value.back() == '/') + { + path.push_back('/'); + } + m_path = std::move(path); +} + +//ugh, this isn't even part of the canonicalization spec. It is part of how our services have implemented their signers though.... +//it doesn't really hurt anything to reorder it though, so go ahead and sort the values for parameters with the same key +void InsertValueOrderedParameter(QueryStringParameterCollection& queryParams, const Aws::String& key, const Aws::String& value) +{ + auto entriesAtKey = queryParams.equal_range(key); + for (auto& entry = entriesAtKey.first; entry != entriesAtKey.second; ++entry) + { + if (entry->second > value) + { + queryParams.emplace_hint(entry, key, value); + return; + } + } + + queryParams.emplace(key, value); +} + +QueryStringParameterCollection URI::GetQueryStringParameters(bool decode) const +{ + Aws::String queryString = GetQueryString(); + + QueryStringParameterCollection parameterCollection; + + //if we actually have a query string + if (queryString.size() > 0) + { + size_t currentPos = 1, locationOfNextDelimiter = 1; + + //while we have params left to parse + while (currentPos < queryString.size()) + { + //find next key/value pair + locationOfNextDelimiter = queryString.find('&', currentPos); + + Aws::String keyValuePair; + + //if this isn't the last parameter + if (locationOfNextDelimiter != Aws::String::npos) + { + keyValuePair = queryString.substr(currentPos, locationOfNextDelimiter - currentPos); + } + //if it is the last parameter + else + { + keyValuePair = queryString.substr(currentPos); + } + + //split on = + size_t locationOfEquals = keyValuePair.find('='); + Aws::String key = keyValuePair.substr(0, locationOfEquals); + Aws::String value = keyValuePair.substr(locationOfEquals + 1); + + if(decode) + { + InsertValueOrderedParameter(parameterCollection, StringUtils::URLDecode(key.c_str()), StringUtils::URLDecode(value.c_str())); + } + else + { + InsertValueOrderedParameter(parameterCollection, key, value); + } + + currentPos += keyValuePair.size() + 1; + } + } + + return parameterCollection; +} + +void URI::CanonicalizeQueryString() +{ + QueryStringParameterCollection sortedParameters = GetQueryStringParameters(false); + Aws::StringStream queryStringStream; + + bool first = true; + + if(sortedParameters.size() > 0) + { + queryStringStream << "?"; + } + + if(m_queryString.find('=') != std::string::npos) + { + for (QueryStringParameterCollection::iterator iter = sortedParameters.begin(); + iter != sortedParameters.end(); ++iter) + { + if (!first) + { + queryStringStream << "&"; + } + + first = false; + queryStringStream << iter->first.c_str() << "=" << iter->second.c_str(); + } + + m_queryString = queryStringStream.str(); + } +} + +void URI::AddQueryStringParameter(const char* key, const Aws::String& value) +{ + if (m_queryString.size() <= 0) + { + m_queryString.append("?"); + } + else + { + m_queryString.append("&"); + } + + m_queryString.append(StringUtils::URLEncode(key) + "=" + StringUtils::URLEncode(value.c_str())); +} + +void URI::AddQueryStringParameter(const Aws::Map<Aws::String, Aws::String>& queryStringPairs) +{ + for(const auto& entry: queryStringPairs) + { + AddQueryStringParameter(entry.first.c_str(), entry.second); + } +} + +void URI::SetQueryString(const Aws::String& str) +{ + m_queryString = ""; + + if (str.empty()) return; + + if (str.front() != '?') + { + m_queryString.append("?").append(str); + } + else + { + m_queryString = str; + } +} + +Aws::String URI::GetURIString(bool includeQueryString) const +{ + assert(m_authority.size() > 0); + + Aws::StringStream ss; + ss << SchemeMapper::ToString(m_scheme) << SEPARATOR << m_authority; + + if (m_scheme == Scheme::HTTP && m_port != HTTP_DEFAULT_PORT) + { + ss << ":" << m_port; + } + else if (m_scheme == Scheme::HTTPS && m_port != HTTPS_DEFAULT_PORT) + { + ss << ":" << m_port; + } + + if(m_path != "/") + { + ss << URLEncodePathRFC3986(m_path); + } + + if(includeQueryString) + { + ss << m_queryString; + } + + return ss.str(); +} + +void URI::ParseURIParts(const Aws::String& uri) +{ + ExtractAndSetScheme(uri); + ExtractAndSetAuthority(uri); + ExtractAndSetPort(uri); + ExtractAndSetPath(uri); + ExtractAndSetQueryString(uri); +} + +void URI::ExtractAndSetScheme(const Aws::String& uri) +{ + size_t posOfSeparator = uri.find(SEPARATOR); + + if (posOfSeparator != Aws::String::npos) + { + Aws::String schemePortion = uri.substr(0, posOfSeparator); + SetScheme(SchemeMapper::FromString(schemePortion.c_str())); + } + else + { + SetScheme(Scheme::HTTP); + } +} + +void URI::ExtractAndSetAuthority(const Aws::String& uri) +{ + size_t authorityStart = uri.find(SEPARATOR); + + if (authorityStart == Aws::String::npos) + { + authorityStart = 0; + } + else + { + authorityStart += 3; + } + + size_t posOfEndOfAuthorityPort = uri.find(':', authorityStart); + size_t posOfEndOfAuthoritySlash = uri.find('/', authorityStart); + size_t posOfEndOfAuthorityQuery = uri.find('?', authorityStart); + size_t posEndOfAuthority = (std::min)({posOfEndOfAuthorityPort, posOfEndOfAuthoritySlash, posOfEndOfAuthorityQuery}); + if (posEndOfAuthority == Aws::String::npos) + { + posEndOfAuthority = uri.length(); + } + + SetAuthority(uri.substr(authorityStart, posEndOfAuthority - authorityStart)); +} + +void URI::ExtractAndSetPort(const Aws::String& uri) +{ + size_t authorityStart = uri.find(SEPARATOR); + + if(authorityStart == Aws::String::npos) + { + authorityStart = 0; + } + else + { + authorityStart += 3; + } + + size_t positionOfPortDelimiter = uri.find(':', authorityStart); + + bool hasPort = positionOfPortDelimiter != Aws::String::npos; + + if ((uri.find('/', authorityStart) < positionOfPortDelimiter) || (uri.find('?', authorityStart) < positionOfPortDelimiter)) + { + hasPort = false; + } + + if (hasPort) + { + Aws::String strPort; + + size_t i = positionOfPortDelimiter + 1; + char currentDigit = uri[i]; + + while (std::isdigit(currentDigit)) + { + strPort += currentDigit; + currentDigit = uri[++i]; + } + + SetPort(static_cast<uint16_t>(atoi(strPort.c_str()))); + } +} + +void URI::ExtractAndSetPath(const Aws::String& uri) +{ + size_t authorityStart = uri.find(SEPARATOR); + + if (authorityStart == Aws::String::npos) + { + authorityStart = 0; + } + else + { + authorityStart += 3; + } + + size_t pathEnd = uri.find('?'); + + if (pathEnd == Aws::String::npos) + { + pathEnd = uri.length(); + } + + Aws::String authorityAndPath = uri.substr(authorityStart, pathEnd - authorityStart); + + size_t pathStart = authorityAndPath.find('/'); + + if (pathStart != Aws::String::npos) + { + SetPath(authorityAndPath.substr(pathStart, pathEnd - pathStart)); + } + else + { + SetPath("/"); + } +} + +void URI::ExtractAndSetQueryString(const Aws::String& uri) +{ + size_t queryStart = uri.find('?'); + + if (queryStart != Aws::String::npos) + { + m_queryString = uri.substr(queryStart); + } +} + +Aws::String URI::GetFormParameters() const +{ + if(m_queryString.length() == 0) + { + return ""; + } + else + { + return m_queryString.substr(1); + } +} + +bool URI::CompareURIParts(const URI& other) const +{ + return m_scheme == other.m_scheme && m_authority == other.m_authority && m_path == other.m_path && m_queryString == other.m_queryString; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/curl/CurlHandleContainer.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/curl/CurlHandleContainer.cpp new file mode 100644 index 0000000000..1a965cd795 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/curl/CurlHandleContainer.cpp @@ -0,0 +1,153 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/http/curl/CurlHandleContainer.h> +#include <aws/core/utils/logging/LogMacros.h> + +#include <algorithm> + +using namespace Aws::Utils::Logging; +using namespace Aws::Http; + +static const char* CURL_HANDLE_CONTAINER_TAG = "CurlHandleContainer"; + + +CurlHandleContainer::CurlHandleContainer(unsigned maxSize, long httpRequestTimeout, long connectTimeout, bool enableTcpKeepAlive, + unsigned long tcpKeepAliveIntervalMs, long lowSpeedTime, unsigned long lowSpeedLimit) : + m_maxPoolSize(maxSize), m_httpRequestTimeout(httpRequestTimeout), m_connectTimeout(connectTimeout), m_enableTcpKeepAlive(enableTcpKeepAlive), + m_tcpKeepAliveIntervalMs(tcpKeepAliveIntervalMs), m_lowSpeedTime(lowSpeedTime), m_lowSpeedLimit(lowSpeedLimit), m_poolSize(0) +{ + AWS_LOGSTREAM_INFO(CURL_HANDLE_CONTAINER_TAG, "Initializing CurlHandleContainer with size " << maxSize); +} + +CurlHandleContainer::~CurlHandleContainer() +{ + AWS_LOGSTREAM_INFO(CURL_HANDLE_CONTAINER_TAG, "Cleaning up CurlHandleContainer."); + for (CURL* handle : m_handleContainer.ShutdownAndWait(m_poolSize)) + { + AWS_LOGSTREAM_DEBUG(CURL_HANDLE_CONTAINER_TAG, "Cleaning up " << handle); + curl_easy_cleanup(handle); + } +} + +CURL* CurlHandleContainer::AcquireCurlHandle() +{ + AWS_LOGSTREAM_DEBUG(CURL_HANDLE_CONTAINER_TAG, "Attempting to acquire curl connection."); + + if(!m_handleContainer.HasResourcesAvailable()) + { + AWS_LOGSTREAM_DEBUG(CURL_HANDLE_CONTAINER_TAG, "No current connections available in pool. Attempting to create new connections."); + CheckAndGrowPool(); + } + + CURL* handle = m_handleContainer.Acquire(); + AWS_LOGSTREAM_INFO(CURL_HANDLE_CONTAINER_TAG, "Connection has been released. Continuing."); + AWS_LOGSTREAM_DEBUG(CURL_HANDLE_CONTAINER_TAG, "Returning connection handle " << handle); + return handle; +} + +void CurlHandleContainer::ReleaseCurlHandle(CURL* handle) +{ + if (handle) + { + curl_easy_reset(handle); + SetDefaultOptionsOnHandle(handle); + AWS_LOGSTREAM_DEBUG(CURL_HANDLE_CONTAINER_TAG, "Releasing curl handle " << handle); + m_handleContainer.Release(handle); + AWS_LOGSTREAM_DEBUG(CURL_HANDLE_CONTAINER_TAG, "Notified waiting threads."); + } +} + +void CurlHandleContainer::DestroyCurlHandle(CURL* handle) +{ + if (!handle) + { + return; + } + + curl_easy_cleanup(handle); + AWS_LOGSTREAM_DEBUG(CURL_HANDLE_CONTAINER_TAG, "Destroy curl handle: " << handle); + { + std::lock_guard<std::mutex> locker(m_containerLock); + // Other threads could be blocked and waiting on m_handleContainer.Acquire() + // If the handle is not released back to the pool, it could create a deadlock + // Create a new handle and release that into the pool + handle = CreateCurlHandleInPool(); + } + if (handle) + { + AWS_LOGSTREAM_DEBUG(CURL_HANDLE_CONTAINER_TAG, "Created replacement handle and released to pool: " << handle); + } +} + + +CURL* CurlHandleContainer::CreateCurlHandleInPool() +{ + CURL* curlHandle = curl_easy_init(); + + if (curlHandle) + { + SetDefaultOptionsOnHandle(curlHandle); + m_handleContainer.Release(curlHandle); + } + else + { + AWS_LOGSTREAM_ERROR(CURL_HANDLE_CONTAINER_TAG, "curl_easy_init failed to allocate."); + } + return curlHandle; +} + +bool CurlHandleContainer::CheckAndGrowPool() +{ + std::lock_guard<std::mutex> locker(m_containerLock); + if (m_poolSize < m_maxPoolSize) + { + unsigned multiplier = m_poolSize > 0 ? m_poolSize : 1; + unsigned amountToAdd = (std::min)(multiplier * 2, m_maxPoolSize - m_poolSize); + AWS_LOGSTREAM_DEBUG(CURL_HANDLE_CONTAINER_TAG, "attempting to grow pool size by " << amountToAdd); + + unsigned actuallyAdded = 0; + for (unsigned i = 0; i < amountToAdd; ++i) + { + CURL* curlHandle = CreateCurlHandleInPool(); + + if (curlHandle) + { + ++actuallyAdded; + } + else + { + break; + } + } + + AWS_LOGSTREAM_INFO(CURL_HANDLE_CONTAINER_TAG, "Pool grown by " << actuallyAdded); + m_poolSize += actuallyAdded; + + return actuallyAdded > 0; + } + + AWS_LOGSTREAM_INFO(CURL_HANDLE_CONTAINER_TAG, "Pool cannot be grown any further, already at max size."); + + return false; +} + +void CurlHandleContainer::SetDefaultOptionsOnHandle(CURL* handle) +{ + //for timeouts to work in a multi-threaded context, + //always turn signals off. This also forces dns queries to + //not be included in the timeout calculations. + curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(handle, CURLOPT_TIMEOUT_MS, m_httpRequestTimeout); + curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT_MS, m_connectTimeout); + curl_easy_setopt(handle, CURLOPT_LOW_SPEED_LIMIT, m_lowSpeedLimit); + curl_easy_setopt(handle, CURLOPT_LOW_SPEED_TIME, m_lowSpeedTime < 1000 ? (m_lowSpeedTime == 0 ? 0 : 1) : m_lowSpeedTime / 1000); + curl_easy_setopt(handle, CURLOPT_TCP_KEEPALIVE, m_enableTcpKeepAlive ? 1L : 0L); + curl_easy_setopt(handle, CURLOPT_TCP_KEEPINTVL, m_tcpKeepAliveIntervalMs / 1000); + curl_easy_setopt(handle, CURLOPT_TCP_KEEPIDLE, m_tcpKeepAliveIntervalMs / 1000); +#ifdef CURL_HAS_H2 + curl_easy_setopt(handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); +#endif +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/curl/CurlHttpClient.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/curl/CurlHttpClient.cpp new file mode 100644 index 0000000000..2fb9cc9643 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/curl/CurlHttpClient.cpp @@ -0,0 +1,730 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/http/curl/CurlHttpClient.h> +#include <aws/core/http/HttpRequest.h> +#include <aws/core/http/standard/StandardHttpResponse.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/ratelimiter/RateLimiterInterface.h> +#include <aws/core/utils/DateTime.h> +#include <aws/core/monitoring/HttpClientMetrics.h> +#include <cassert> +#include <algorithm> + + +using namespace Aws::Client; +using namespace Aws::Http; +using namespace Aws::Http::Standard; +using namespace Aws::Utils; +using namespace Aws::Utils::Logging; +using namespace Aws::Monitoring; + +#ifdef AWS_CUSTOM_MEMORY_MANAGEMENT + +static const char* MemTag = "libcurl"; +static size_t offset = sizeof(size_t); + +static void* malloc_callback(size_t size) +{ + char* newMem = reinterpret_cast<char*>(Aws::Malloc(MemTag, size + offset)); + std::size_t* pointerToSize = reinterpret_cast<std::size_t*>(newMem); + *pointerToSize = size; + return reinterpret_cast<void*>(newMem + offset); +} + +static void free_callback(void* ptr) +{ + if(ptr) + { + char* shiftedMemory = reinterpret_cast<char*>(ptr); + Aws::Free(shiftedMemory - offset); + } +} + +static void* realloc_callback(void* ptr, size_t size) +{ + if(!ptr) + { + return malloc_callback(size); + } + + + if(!size && ptr) + { + free_callback(ptr); + return nullptr; + } + + char* originalLenCharPtr = reinterpret_cast<char*>(ptr) - offset; + size_t originalLen = *reinterpret_cast<size_t*>(originalLenCharPtr); + + char* rawMemory = reinterpret_cast<char*>(Aws::Malloc(MemTag, size + offset)); + if(rawMemory) + { + std::size_t* pointerToSize = reinterpret_cast<std::size_t*>(rawMemory); + *pointerToSize = size; + + size_t copyLength = (std::min)(originalLen, size); +#ifdef _MSC_VER + memcpy_s(rawMemory + offset, size, ptr, copyLength); +#else + memcpy(rawMemory + offset, ptr, copyLength); +#endif + free_callback(ptr); + return reinterpret_cast<void*>(rawMemory + offset); + } + else + { + return ptr; + } + +} + +static void* calloc_callback(size_t nmemb, size_t size) +{ + size_t dataSize = nmemb * size; + char* newMem = reinterpret_cast<char*>(Aws::Malloc(MemTag, dataSize + offset)); + std::size_t* pointerToSize = reinterpret_cast<std::size_t*>(newMem); + *pointerToSize = dataSize; +#ifdef _MSC_VER + memset_s(newMem + offset, dataSize, 0, dataSize); +#else + memset(newMem + offset, 0, dataSize); +#endif + + return reinterpret_cast<void*>(newMem + offset); +} + +static char* strdup_callback(const char* str) +{ + size_t len = strlen(str) + 1; + size_t newLen = len + offset; + char* newMem = reinterpret_cast<char*>(Aws::Malloc(MemTag, newLen)); + + if(newMem) + { + std::size_t* pointerToSize = reinterpret_cast<std::size_t*>(newMem); + *pointerToSize = len; +#ifdef _MSC_VER + memcpy_s(newMem + offset, len, str, len); +#else + memcpy(newMem + offset, str, len); +#endif + return newMem + offset; + } + return nullptr; +} + +#endif + +struct CurlWriteCallbackContext +{ + CurlWriteCallbackContext(const CurlHttpClient* client, + HttpRequest* request, + HttpResponse* response, + Aws::Utils::RateLimits::RateLimiterInterface* rateLimiter) : + m_client(client), + m_request(request), + m_response(response), + m_rateLimiter(rateLimiter), + m_numBytesResponseReceived(0) + {} + + const CurlHttpClient* m_client; + HttpRequest* m_request; + HttpResponse* m_response; + Aws::Utils::RateLimits::RateLimiterInterface* m_rateLimiter; + int64_t m_numBytesResponseReceived; +}; + +struct CurlReadCallbackContext +{ + CurlReadCallbackContext(const CurlHttpClient* client, HttpRequest* request, Aws::Utils::RateLimits::RateLimiterInterface* limiter) : + m_client(client), + m_rateLimiter(limiter), + m_request(request) + {} + + const CurlHttpClient* m_client; + CURL* m_curlHandle; + Aws::Utils::RateLimits::RateLimiterInterface* m_rateLimiter; + HttpRequest* m_request; +}; + +static const char* CURL_HTTP_CLIENT_TAG = "CurlHttpClient"; + +static size_t WriteData(char* ptr, size_t size, size_t nmemb, void* userdata) +{ + if (ptr) + { + CurlWriteCallbackContext* context = reinterpret_cast<CurlWriteCallbackContext*>(userdata); + + const CurlHttpClient* client = context->m_client; + if(!client->ContinueRequest(*context->m_request) || !client->IsRequestProcessingEnabled()) + { + return 0; + } + + HttpResponse* response = context->m_response; + size_t sizeToWrite = size * nmemb; + if (context->m_rateLimiter) + { + context->m_rateLimiter->ApplyAndPayForCost(static_cast<int64_t>(sizeToWrite)); + } + + response->GetResponseBody().write(ptr, static_cast<std::streamsize>(sizeToWrite)); + if (context->m_request->IsEventStreamRequest()) + { + response->GetResponseBody().flush(); + } + auto& receivedHandler = context->m_request->GetDataReceivedEventHandler(); + if (receivedHandler) + { + receivedHandler(context->m_request, context->m_response, static_cast<long long>(sizeToWrite)); + } + + AWS_LOGSTREAM_TRACE(CURL_HTTP_CLIENT_TAG, sizeToWrite << " bytes written to response."); + context->m_numBytesResponseReceived += sizeToWrite; + return sizeToWrite; + } + return 0; +} + +static size_t WriteHeader(char* ptr, size_t size, size_t nmemb, void* userdata) +{ + if (ptr) + { + CurlWriteCallbackContext* context = reinterpret_cast<CurlWriteCallbackContext*>(userdata); + AWS_LOGSTREAM_TRACE(CURL_HTTP_CLIENT_TAG, ptr); + HttpResponse* response = context->m_response; + Aws::String headerLine(ptr); + Aws::Vector<Aws::String> keyValuePair = StringUtils::Split(headerLine, ':', 2); + + if (keyValuePair.size() == 2) + { + response->AddHeader(StringUtils::Trim(keyValuePair[0].c_str()), StringUtils::Trim(keyValuePair[1].c_str())); + } + + return size * nmemb; + } + return 0; +} + + +static size_t ReadBody(char* ptr, size_t size, size_t nmemb, void* userdata) +{ + CurlReadCallbackContext* context = reinterpret_cast<CurlReadCallbackContext*>(userdata); + if(context == nullptr) + { + return 0; + } + + const CurlHttpClient* client = context->m_client; + if(!client->ContinueRequest(*context->m_request) || !client->IsRequestProcessingEnabled()) + { + return CURL_READFUNC_ABORT; + } + + HttpRequest* request = context->m_request; + const std::shared_ptr<Aws::IOStream>& ioStream = request->GetContentBody(); + + const size_t amountToRead = size * nmemb; + if (ioStream != nullptr && amountToRead > 0) + { + if (request->IsEventStreamRequest()) + { + // Waiting for next available character to read. + // Without peek(), readsome() will keep reading 0 byte from the stream. + ioStream->peek(); + ioStream->readsome(ptr, amountToRead); + } + else + { + ioStream->read(ptr, amountToRead); + } + size_t amountRead = static_cast<size_t>(ioStream->gcount()); + auto& sentHandler = request->GetDataSentEventHandler(); + if (sentHandler) + { + sentHandler(request, static_cast<long long>(amountRead)); + } + + if (context->m_rateLimiter) + { + context->m_rateLimiter->ApplyAndPayForCost(static_cast<int64_t>(amountRead)); + } + + return amountRead; + } + + return 0; +} + +static size_t SeekBody(void* userdata, curl_off_t offset, int origin) +{ + CurlReadCallbackContext* context = reinterpret_cast<CurlReadCallbackContext*>(userdata); + if(context == nullptr) + { + return CURL_SEEKFUNC_FAIL; + } + + const CurlHttpClient* client = context->m_client; + if(!client->ContinueRequest(*context->m_request) || !client->IsRequestProcessingEnabled()) + { + return CURL_SEEKFUNC_FAIL; + } + + HttpRequest* request = context->m_request; + const std::shared_ptr<Aws::IOStream>& ioStream = request->GetContentBody(); + + std::ios_base::seekdir dir; + switch(origin) + { + case SEEK_SET: + dir = std::ios_base::beg; + break; + case SEEK_CUR: + dir = std::ios_base::cur; + break; + case SEEK_END: + dir = std::ios_base::end; + break; + default: + return CURL_SEEKFUNC_FAIL; + } + + ioStream->clear(); + ioStream->seekg(offset, dir); + if (ioStream->fail()) { + return CURL_SEEKFUNC_CANTSEEK; + } + + return CURL_SEEKFUNC_OK; +} + +void SetOptCodeForHttpMethod(CURL* requestHandle, const std::shared_ptr<HttpRequest>& request) +{ + switch (request->GetMethod()) + { + case HttpMethod::HTTP_GET: + curl_easy_setopt(requestHandle, CURLOPT_HTTPGET, 1L); + break; + case HttpMethod::HTTP_POST: + if (request->HasHeader(Aws::Http::CONTENT_LENGTH_HEADER) && request->GetHeaderValue(Aws::Http::CONTENT_LENGTH_HEADER) == "0") + { + curl_easy_setopt(requestHandle, CURLOPT_CUSTOMREQUEST, "POST"); + } + else + { + curl_easy_setopt(requestHandle, CURLOPT_POST, 1L); + } + break; + case HttpMethod::HTTP_PUT: + if ((!request->HasHeader(Aws::Http::CONTENT_LENGTH_HEADER) || request->GetHeaderValue(Aws::Http::CONTENT_LENGTH_HEADER) == "0") && + !request->HasHeader(Aws::Http::TRANSFER_ENCODING_HEADER)) + { + curl_easy_setopt(requestHandle, CURLOPT_CUSTOMREQUEST, "PUT"); + } + else + { + curl_easy_setopt(requestHandle, CURLOPT_PUT, 1L); + } + break; + case HttpMethod::HTTP_HEAD: + curl_easy_setopt(requestHandle, CURLOPT_HTTPGET, 1L); + curl_easy_setopt(requestHandle, CURLOPT_NOBODY, 1L); + break; + case HttpMethod::HTTP_PATCH: + if ((!request->HasHeader(Aws::Http::CONTENT_LENGTH_HEADER)|| request->GetHeaderValue(Aws::Http::CONTENT_LENGTH_HEADER) == "0") && + !request->HasHeader(Aws::Http::TRANSFER_ENCODING_HEADER)) + { + curl_easy_setopt(requestHandle, CURLOPT_CUSTOMREQUEST, "PATCH"); + } + else + { + curl_easy_setopt(requestHandle, CURLOPT_POST, 1L); + curl_easy_setopt(requestHandle, CURLOPT_CUSTOMREQUEST, "PATCH"); + } + + break; + case HttpMethod::HTTP_DELETE: + curl_easy_setopt(requestHandle, CURLOPT_CUSTOMREQUEST, "DELETE"); + break; + default: + assert(0); + curl_easy_setopt(requestHandle, CURLOPT_CUSTOMREQUEST, "GET"); + break; + } +} + + +std::atomic<bool> CurlHttpClient::isInit(false); + +void CurlHttpClient::InitGlobalState() +{ + if (!isInit) + { + auto curlVersionData = curl_version_info(CURLVERSION_NOW); + AWS_LOGSTREAM_INFO(CURL_HTTP_CLIENT_TAG, "Initializing Curl library with version: " << curlVersionData->version + << ", ssl version: " << curlVersionData->ssl_version); + isInit = true; +#ifdef AWS_CUSTOM_MEMORY_MANAGEMENT + curl_global_init_mem(CURL_GLOBAL_ALL, &malloc_callback, &free_callback, &realloc_callback, &strdup_callback, &calloc_callback); +#else + curl_global_init(CURL_GLOBAL_ALL); +#endif + } +} + + +void CurlHttpClient::CleanupGlobalState() +{ + curl_global_cleanup(); +} + +Aws::String CurlInfoTypeToString(curl_infotype type) +{ + switch(type) + { + case CURLINFO_TEXT: + return "Text"; + + case CURLINFO_HEADER_IN: + return "HeaderIn"; + + case CURLINFO_HEADER_OUT: + return "HeaderOut"; + + case CURLINFO_DATA_IN: + return "DataIn"; + + case CURLINFO_DATA_OUT: + return "DataOut"; + + case CURLINFO_SSL_DATA_IN: + return "SSLDataIn"; + + case CURLINFO_SSL_DATA_OUT: + return "SSLDataOut"; + + default: + return "Unknown"; + } +} + +int CurlDebugCallback(CURL *handle, curl_infotype type, char *data, size_t size, void *userptr) +{ + AWS_UNREFERENCED_PARAM(handle); + AWS_UNREFERENCED_PARAM(userptr); + + if(type == CURLINFO_SSL_DATA_IN || type == CURLINFO_SSL_DATA_OUT) + { + AWS_LOGSTREAM_DEBUG("CURL", "(" << CurlInfoTypeToString(type) << ") " << size << "bytes"); + } + else + { + Aws::String debugString(data, size); + AWS_LOGSTREAM_DEBUG("CURL", "(" << CurlInfoTypeToString(type) << ") " << debugString); + } + + return 0; +} + + +CurlHttpClient::CurlHttpClient(const ClientConfiguration& clientConfig) : + Base(), + m_curlHandleContainer(clientConfig.maxConnections, clientConfig.httpRequestTimeoutMs, clientConfig.connectTimeoutMs, clientConfig.enableTcpKeepAlive, + clientConfig.tcpKeepAliveIntervalMs, clientConfig.requestTimeoutMs, clientConfig.lowSpeedLimit), + m_isUsingProxy(!clientConfig.proxyHost.empty()), m_proxyUserName(clientConfig.proxyUserName), + m_proxyPassword(clientConfig.proxyPassword), m_proxyScheme(SchemeMapper::ToString(clientConfig.proxyScheme)), m_proxyHost(clientConfig.proxyHost), + m_proxySSLCertPath(clientConfig.proxySSLCertPath), m_proxySSLCertType(clientConfig.proxySSLCertType), + m_proxySSLKeyPath(clientConfig.proxySSLKeyPath), m_proxySSLKeyType(clientConfig.proxySSLKeyType), + m_proxyKeyPasswd(clientConfig.proxySSLKeyPassword), + m_proxyPort(clientConfig.proxyPort), m_verifySSL(clientConfig.verifySSL), m_caPath(clientConfig.caPath), + m_caFile(clientConfig.caFile), m_proxyCaPath(clientConfig.proxyCaPath), m_proxyCaFile(clientConfig.proxyCaFile), + m_disableExpectHeader(clientConfig.disableExpectHeader) +{ + if (clientConfig.followRedirects == FollowRedirectsPolicy::NEVER || + (clientConfig.followRedirects == FollowRedirectsPolicy::DEFAULT && clientConfig.region == Aws::Region::AWS_GLOBAL)) + { + m_allowRedirects = false; + } + else + { + m_allowRedirects = true; + } +} + + +std::shared_ptr<HttpResponse> CurlHttpClient::MakeRequest(const std::shared_ptr<HttpRequest>& request, + Aws::Utils::RateLimits::RateLimiterInterface* readLimiter, + Aws::Utils::RateLimits::RateLimiterInterface* writeLimiter) const +{ + URI uri = request->GetUri(); + Aws::String url = uri.GetURIString(); + std::shared_ptr<HttpResponse> response = Aws::MakeShared<StandardHttpResponse>(CURL_HTTP_CLIENT_TAG, request); + + AWS_LOGSTREAM_TRACE(CURL_HTTP_CLIENT_TAG, "Making request to " << url); + struct curl_slist* headers = NULL; + + if (writeLimiter != nullptr) + { + writeLimiter->ApplyAndPayForCost(request->GetSize()); + } + + Aws::StringStream headerStream; + HeaderValueCollection requestHeaders = request->GetHeaders(); + + AWS_LOGSTREAM_TRACE(CURL_HTTP_CLIENT_TAG, "Including headers:"); + for (auto& requestHeader : requestHeaders) + { + headerStream.str(""); + headerStream << requestHeader.first << ": " << requestHeader.second; + Aws::String headerString = headerStream.str(); + AWS_LOGSTREAM_TRACE(CURL_HTTP_CLIENT_TAG, headerString); + headers = curl_slist_append(headers, headerString.c_str()); + } + + if (!request->HasHeader(Http::TRANSFER_ENCODING_HEADER)) + { + headers = curl_slist_append(headers, "transfer-encoding:"); + } + + if (!request->HasHeader(Http::CONTENT_LENGTH_HEADER)) + { + headers = curl_slist_append(headers, "content-length:"); + } + + if (!request->HasHeader(Http::CONTENT_TYPE_HEADER)) + { + headers = curl_slist_append(headers, "content-type:"); + } + + // Discard Expect header so as to avoid using multiple payloads to send a http request (header + body) + if (m_disableExpectHeader) + { + headers = curl_slist_append(headers, "Expect:"); + } + + CURL* connectionHandle = m_curlHandleContainer.AcquireCurlHandle(); + + if (connectionHandle) + { + AWS_LOGSTREAM_DEBUG(CURL_HTTP_CLIENT_TAG, "Obtained connection handle " << connectionHandle); + + if (headers) + { + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, headers); + } + + CurlWriteCallbackContext writeContext(this, request.get(), response.get(), readLimiter); + CurlReadCallbackContext readContext(this, request.get(), writeLimiter); + + SetOptCodeForHttpMethod(connectionHandle, request); + + curl_easy_setopt(connectionHandle, CURLOPT_URL, url.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_WRITEFUNCTION, WriteData); + curl_easy_setopt(connectionHandle, CURLOPT_WRITEDATA, &writeContext); + curl_easy_setopt(connectionHandle, CURLOPT_HEADERFUNCTION, WriteHeader); + curl_easy_setopt(connectionHandle, CURLOPT_HEADERDATA, &writeContext); + + //we only want to override the default path if someone has explicitly told us to. + if(!m_caPath.empty()) + { + curl_easy_setopt(connectionHandle, CURLOPT_CAPATH, m_caPath.c_str()); + } + if(!m_caFile.empty()) + { + curl_easy_setopt(connectionHandle, CURLOPT_CAINFO, m_caFile.c_str()); + } + + // only set by android test builds because the emulator is missing a cert needed for aws services +#ifdef TEST_CERT_PATH + curl_easy_setopt(connectionHandle, CURLOPT_CAPATH, TEST_CERT_PATH); +#endif // TEST_CERT_PATH + + if (m_verifySSL) + { + curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYPEER, 1L); + curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYHOST, 2L); + +#if LIBCURL_VERSION_MAJOR >= 7 +#if LIBCURL_VERSION_MINOR >= 34 + curl_easy_setopt(connectionHandle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); +#endif //LIBCURL_VERSION_MINOR +#endif //LIBCURL_VERSION_MAJOR + } + else + { + curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYHOST, 0L); + } + + if (m_allowRedirects) + { + curl_easy_setopt(connectionHandle, CURLOPT_FOLLOWLOCATION, 1L); + } + else + { + curl_easy_setopt(connectionHandle, CURLOPT_FOLLOWLOCATION, 0L); + } + +#ifdef ENABLE_CURL_LOGGING + curl_easy_setopt(connectionHandle, CURLOPT_VERBOSE, 1); + curl_easy_setopt(connectionHandle, CURLOPT_DEBUGFUNCTION, CurlDebugCallback); +#endif + if (m_isUsingProxy) + { + Aws::StringStream ss; + ss << m_proxyScheme << "://" << m_proxyHost; + curl_easy_setopt(connectionHandle, CURLOPT_PROXY, ss.str().c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_PROXYPORT, (long) m_proxyPort); + if(!m_proxyCaPath.empty()) + { + curl_easy_setopt(connectionHandle, CURLOPT_PROXY_CAPATH, m_proxyCaPath.c_str()); + } + if(!m_proxyCaFile.empty()) + { + curl_easy_setopt(connectionHandle, CURLOPT_PROXY_CAINFO, m_proxyCaFile.c_str()); + } + if (!m_proxyUserName.empty() || !m_proxyPassword.empty()) + { + curl_easy_setopt(connectionHandle, CURLOPT_PROXYUSERNAME, m_proxyUserName.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_PROXYPASSWORD, m_proxyPassword.c_str()); + } +#ifdef CURL_HAS_TLS_PROXY + if (!m_proxySSLCertPath.empty()) + { + curl_easy_setopt(connectionHandle, CURLOPT_PROXY_SSLCERT, m_proxySSLCertPath.c_str()); + if (!m_proxySSLCertType.empty()) + { + curl_easy_setopt(connectionHandle, CURLOPT_PROXY_SSLCERTTYPE, m_proxySSLCertType.c_str()); + } + } + if (!m_proxySSLKeyPath.empty()) + { + curl_easy_setopt(connectionHandle, CURLOPT_PROXY_SSLKEY, m_proxySSLKeyPath.c_str()); + if (!m_proxySSLKeyType.empty()) + { + curl_easy_setopt(connectionHandle, CURLOPT_PROXY_SSLKEYTYPE, m_proxySSLKeyType.c_str()); + } + if (!m_proxyKeyPasswd.empty()) + { + curl_easy_setopt(connectionHandle, CURLOPT_PROXY_KEYPASSWD, m_proxyKeyPasswd.c_str()); + } + } +#endif //CURL_HAS_TLS_PROXY + } + else + { + curl_easy_setopt(connectionHandle, CURLOPT_PROXY, ""); + } + + if (request->GetContentBody()) + { + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, ReadBody); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &readContext); + curl_easy_setopt(connectionHandle, CURLOPT_SEEKFUNCTION, SeekBody); + curl_easy_setopt(connectionHandle, CURLOPT_SEEKDATA, &readContext); + } + + OverrideOptionsOnConnectionHandle(connectionHandle); + Aws::Utils::DateTime startTransmissionTime = Aws::Utils::DateTime::Now(); + CURLcode curlResponseCode = curl_easy_perform(connectionHandle); + bool shouldContinueRequest = ContinueRequest(*request); + if (curlResponseCode != CURLE_OK && shouldContinueRequest) + { + response->SetClientErrorType(CoreErrors::NETWORK_CONNECTION); + Aws::StringStream ss; + ss << "curlCode: " << curlResponseCode << ", " << curl_easy_strerror(curlResponseCode); + response->SetClientErrorMessage(ss.str()); + AWS_LOGSTREAM_ERROR(CURL_HTTP_CLIENT_TAG, "Curl returned error code " << curlResponseCode + << " - " << curl_easy_strerror(curlResponseCode)); + } + else if(!shouldContinueRequest) + { + response->SetClientErrorType(CoreErrors::USER_CANCELLED); + response->SetClientErrorMessage("Request cancelled by user's continuation handler"); + } + else + { + long responseCode; + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &responseCode); + response->SetResponseCode(static_cast<HttpResponseCode>(responseCode)); + AWS_LOGSTREAM_DEBUG(CURL_HTTP_CLIENT_TAG, "Returned http response code " << responseCode); + + char* contentType = nullptr; + curl_easy_getinfo(connectionHandle, CURLINFO_CONTENT_TYPE, &contentType); + if (contentType) + { + response->SetContentType(contentType); + AWS_LOGSTREAM_DEBUG(CURL_HTTP_CLIENT_TAG, "Returned content type " << contentType); + } + + if (request->GetMethod() != HttpMethod::HTTP_HEAD && + writeContext.m_client->IsRequestProcessingEnabled() && + response->HasHeader(Aws::Http::CONTENT_LENGTH_HEADER)) + { + const Aws::String& contentLength = response->GetHeader(Aws::Http::CONTENT_LENGTH_HEADER); + int64_t numBytesResponseReceived = writeContext.m_numBytesResponseReceived; + AWS_LOGSTREAM_TRACE(CURL_HTTP_CLIENT_TAG, "Response content-length header: " << contentLength); + AWS_LOGSTREAM_TRACE(CURL_HTTP_CLIENT_TAG, "Response body length: " << numBytesResponseReceived); + if (StringUtils::ConvertToInt64(contentLength.c_str()) != numBytesResponseReceived) + { + response->SetClientErrorType(CoreErrors::NETWORK_CONNECTION); + response->SetClientErrorMessage("Response body length doesn't match the content-length header."); + AWS_LOGSTREAM_ERROR(CURL_HTTP_CLIENT_TAG, "Response body length doesn't match the content-length header."); + } + } + + AWS_LOGSTREAM_DEBUG(CURL_HTTP_CLIENT_TAG, "Releasing curl handle " << connectionHandle); + } + + double timep; + CURLcode ret = curl_easy_getinfo(connectionHandle, CURLINFO_NAMELOOKUP_TIME, &timep); // DNS Resolve Latency, seconds. + if (ret == CURLE_OK) + { + request->AddRequestMetric(GetHttpClientMetricNameByType(HttpClientMetricsType::DnsLatency), static_cast<int64_t>(timep * 1000));// to milliseconds + } + + ret = curl_easy_getinfo(connectionHandle, CURLINFO_STARTTRANSFER_TIME, &timep); // Connect Latency + if (ret == CURLE_OK) + { + request->AddRequestMetric(GetHttpClientMetricNameByType(HttpClientMetricsType::ConnectLatency), static_cast<int64_t>(timep * 1000)); + } + + ret = curl_easy_getinfo(connectionHandle, CURLINFO_APPCONNECT_TIME, &timep); // Ssl Latency + if (ret == CURLE_OK) + { + request->AddRequestMetric(GetHttpClientMetricNameByType(HttpClientMetricsType::SslLatency), static_cast<int64_t>(timep * 1000)); + } + + const char* ip = nullptr; + auto curlGetInfoResult = curl_easy_getinfo(connectionHandle, CURLINFO_PRIMARY_IP, &ip); // Get the IP address of the remote endpoint + if (curlGetInfoResult == CURLE_OK && ip) + { + request->SetResolvedRemoteHost(ip); + } + if (curlResponseCode != CURLE_OK) + { + m_curlHandleContainer.DestroyCurlHandle(connectionHandle); + } + else + { + m_curlHandleContainer.ReleaseCurlHandle(connectionHandle); + } + //go ahead and flush the response body stream + response->GetResponseBody().flush(); + request->AddRequestMetric(GetHttpClientMetricNameByType(HttpClientMetricsType::RequestLatency), (DateTime::Now() - startTransmissionTime).count()); + } + + if (headers) + { + curl_slist_free_all(headers); + } + + return response; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/standard/StandardHttpRequest.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/standard/StandardHttpRequest.cpp new file mode 100644 index 0000000000..47a0ee4fac --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/standard/StandardHttpRequest.cpp @@ -0,0 +1,104 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/http/standard/StandardHttpRequest.h> + +#include <aws/core/utils/StringUtils.h> + +#include <iostream> +#include <algorithm> +#include <cassert> + +using namespace Aws::Http; +using namespace Aws::Http::Standard; +using namespace Aws::Utils; + +static bool IsDefaultPort(const URI& uri) +{ + switch(uri.GetPort()) + { + case 80: + return uri.GetScheme() == Scheme::HTTP; + case 443: + return uri.GetScheme() == Scheme::HTTPS; + default: + return false; + } +} + +StandardHttpRequest::StandardHttpRequest(const URI& uri, HttpMethod method) : + HttpRequest(uri, method), + bodyStream(nullptr), + m_responseStreamFactory() +{ + if(IsDefaultPort(uri)) + { + StandardHttpRequest::SetHeaderValue(HOST_HEADER, uri.GetAuthority()); + } + else + { + Aws::StringStream host; + host << uri.GetAuthority() << ":" << uri.GetPort(); + StandardHttpRequest::SetHeaderValue(HOST_HEADER, host.str()); + } +} + +HeaderValueCollection StandardHttpRequest::GetHeaders() const +{ + HeaderValueCollection headers; + + for (HeaderValueCollection::const_iterator iter = headerMap.begin(); iter != headerMap.end(); ++iter) + { + headers.emplace(HeaderValuePair(iter->first, iter->second)); + } + + return headers; +} + +const Aws::String& StandardHttpRequest::GetHeaderValue(const char* headerName) const +{ + auto iter = headerMap.find(headerName); + assert (iter != headerMap.end()); + return iter->second; +} + +void StandardHttpRequest::SetHeaderValue(const char* headerName, const Aws::String& headerValue) +{ + headerMap[StringUtils::ToLower(headerName)] = StringUtils::Trim(headerValue.c_str()); +} + +void StandardHttpRequest::SetHeaderValue(const Aws::String& headerName, const Aws::String& headerValue) +{ + headerMap[StringUtils::ToLower(headerName.c_str())] = StringUtils::Trim(headerValue.c_str()); +} + +void StandardHttpRequest::DeleteHeader(const char* headerName) +{ + headerMap.erase(StringUtils::ToLower(headerName)); +} + +bool StandardHttpRequest::HasHeader(const char* headerName) const +{ + return headerMap.find(StringUtils::ToLower(headerName)) != headerMap.end(); +} + +int64_t StandardHttpRequest::GetSize() const +{ + int64_t size = 0; + + std::for_each(headerMap.cbegin(), headerMap.cend(), [&](const HeaderValueCollection::value_type& kvPair){ size += kvPair.first.length(); size += kvPair.second.length(); }); + + return size; +} + +const Aws::IOStreamFactory& StandardHttpRequest::GetResponseStreamFactory() const +{ + return m_responseStreamFactory; +} + +void StandardHttpRequest::SetResponseStreamFactory(const Aws::IOStreamFactory& factory) +{ + m_responseStreamFactory = factory; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/standard/StandardHttpResponse.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/standard/StandardHttpResponse.cpp new file mode 100644 index 0000000000..92d7a062b6 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/standard/StandardHttpResponse.cpp @@ -0,0 +1,46 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/http/standard/StandardHttpResponse.h> + +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/memory/AWSMemory.h> + +#include <istream> + +using namespace Aws::Http; +using namespace Aws::Http::Standard; +using namespace Aws::Utils; + + +HeaderValueCollection StandardHttpResponse::GetHeaders() const +{ + HeaderValueCollection headerValueCollection; + + for (Aws::Map<Aws::String, Aws::String>::const_iterator iter = headerMap.begin(); iter != headerMap.end(); ++iter) + { + headerValueCollection.emplace(HeaderValuePair(iter->first, iter->second)); + } + + return headerValueCollection; +} + +bool StandardHttpResponse::HasHeader(const char* headerName) const +{ + return headerMap.find(StringUtils::ToLower(headerName)) != headerMap.end(); +} + +const Aws::String& StandardHttpResponse::GetHeader(const Aws::String& headerName) const +{ + Aws::Map<Aws::String, Aws::String>::const_iterator foundValue = headerMap.find(StringUtils::ToLower(headerName.c_str())); + return foundValue->second; +} + +void StandardHttpResponse::AddHeader(const Aws::String& headerName, const Aws::String& headerValue) +{ + headerMap[StringUtils::ToLower(headerName.c_str())] = headerValue; +} + + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/internal/AWSHttpResourceClient.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/internal/AWSHttpResourceClient.cpp new file mode 100644 index 0000000000..24145e4d92 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/internal/AWSHttpResourceClient.cpp @@ -0,0 +1,506 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/internal/AWSHttpResourceClient.h> +#include <aws/core/client/DefaultRetryStrategy.h> +#include <aws/core/http/HttpClient.h> +#include <aws/core/http/HttpClientFactory.h> +#include <aws/core/http/HttpResponse.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/HashingUtils.h> +#include <aws/core/platform/Environment.h> +#include <aws/core/client/AWSError.h> +#include <aws/core/client/CoreErrors.h> +#include <aws/core/utils/xml/XmlSerializer.h> +#include <mutex> +#include <sstream> + +using namespace Aws; +using namespace Aws::Utils; +using namespace Aws::Utils::Logging; +using namespace Aws::Utils::Xml; +using namespace Aws::Http; +using namespace Aws::Client; +using namespace Aws::Internal; + +static const char EC2_SECURITY_CREDENTIALS_RESOURCE[] = "/latest/meta-data/iam/security-credentials"; +static const char EC2_REGION_RESOURCE[] = "/latest/meta-data/placement/availability-zone"; +static const char EC2_IMDS_TOKEN_RESOURCE[] = "/latest/api/token"; +static const char EC2_IMDS_TOKEN_TTL_DEFAULT_VALUE[] = "21600"; +static const char EC2_IMDS_TOKEN_TTL_HEADER[] = "x-aws-ec2-metadata-token-ttl-seconds"; +static const char EC2_IMDS_TOKEN_HEADER[] = "x-aws-ec2-metadata-token"; +static const char RESOURCE_CLIENT_CONFIGURATION_ALLOCATION_TAG[] = "AWSHttpResourceClient"; +static const char EC2_METADATA_CLIENT_LOG_TAG[] = "EC2MetadataClient"; +static const char ECS_CREDENTIALS_CLIENT_LOG_TAG[] = "ECSCredentialsClient"; + +namespace Aws +{ + namespace Client + { + Aws::String ComputeUserAgentString(); + } + + namespace Internal + { + static ClientConfiguration MakeDefaultHttpResourceClientConfiguration(const char *logtag) + { + ClientConfiguration res; + + res.maxConnections = 2; + res.scheme = Scheme::HTTP; + + #if defined(WIN32) && defined(BYPASS_DEFAULT_PROXY) + // For security reasons, we must bypass any proxy settings when fetching sensitive information, for example + // user credentials. On Windows, IXMLHttpRequest2 does not support bypassing proxy settings, therefore, + // we force using WinHTTP client. On POSIX systems, CURL is set to bypass proxy settings by default. + res.httpLibOverride = TransferLibType::WIN_HTTP_CLIENT; + AWS_LOGSTREAM_INFO(logtag, "Overriding the current HTTP client to WinHTTP to bypass proxy settings."); + #else + (void) logtag; // To disable warning about unused variable + #endif + // Explicitly set the proxy settings to empty/zero to avoid relying on defaults that could potentially change + // in the future. + res.proxyHost = ""; + res.proxyUserName = ""; + res.proxyPassword = ""; + res.proxyPort = 0; + + // EC2MetadataService throttles by delaying the response so the service client should set a large read timeout. + // EC2MetadataService delay is in order of seconds so it only make sense to retry after a couple of seconds. + res.connectTimeoutMs = 1000; + res.requestTimeoutMs = 1000; + res.retryStrategy = Aws::MakeShared<DefaultRetryStrategy>(RESOURCE_CLIENT_CONFIGURATION_ALLOCATION_TAG, 1, 1000); + + return res; + } + + AWSHttpResourceClient::AWSHttpResourceClient(const Aws::Client::ClientConfiguration& clientConfiguration, const char* logtag) + : m_logtag(logtag), m_retryStrategy(clientConfiguration.retryStrategy), m_httpClient(nullptr) + { + AWS_LOGSTREAM_INFO(m_logtag.c_str(), + "Creating AWSHttpResourceClient with max connections " + << clientConfiguration.maxConnections + << " and scheme " + << SchemeMapper::ToString(clientConfiguration.scheme)); + + m_httpClient = CreateHttpClient(clientConfiguration); + } + + AWSHttpResourceClient::AWSHttpResourceClient(const char* logtag) + : AWSHttpResourceClient(MakeDefaultHttpResourceClientConfiguration(logtag), logtag) + { + } + + AWSHttpResourceClient::~AWSHttpResourceClient() + { + } + + Aws::String AWSHttpResourceClient::GetResource(const char* endpoint, const char* resource, const char* authToken) const + { + return GetResourceWithAWSWebServiceResult(endpoint, resource, authToken).GetPayload(); + } + + AmazonWebServiceResult<Aws::String> AWSHttpResourceClient::GetResourceWithAWSWebServiceResult(const char *endpoint, const char *resource, const char *authToken) const + { + Aws::StringStream ss; + ss << endpoint; + if (resource) + { + ss << resource; + } + std::shared_ptr<HttpRequest> request(CreateHttpRequest(ss.str(), HttpMethod::HTTP_GET, + Aws::Utils::Stream::DefaultResponseStreamFactoryMethod)); + + request->SetUserAgent(ComputeUserAgentString()); + + if (authToken) + { + request->SetHeaderValue(Aws::Http::AWS_AUTHORIZATION_HEADER, authToken); + } + + return GetResourceWithAWSWebServiceResult(request); + } + + AmazonWebServiceResult<Aws::String> AWSHttpResourceClient::GetResourceWithAWSWebServiceResult(const std::shared_ptr<HttpRequest> &httpRequest) const + { + AWS_LOGSTREAM_TRACE(m_logtag.c_str(), "Retrieving credentials from " << httpRequest->GetURIString()); + + for (long retries = 0;; retries++) + { + std::shared_ptr<HttpResponse> response(m_httpClient->MakeRequest(httpRequest)); + + if (response->GetResponseCode() == HttpResponseCode::OK) + { + Aws::IStreamBufIterator eos; + return {Aws::String(Aws::IStreamBufIterator(response->GetResponseBody()), eos), response->GetHeaders(), HttpResponseCode::OK}; + } + + const Aws::Client::AWSError<Aws::Client::CoreErrors> error = [this, &response]() { + if (response->HasClientError() || response->GetResponseBody().tellp() < 1) + { + AWS_LOGSTREAM_ERROR(m_logtag.c_str(), "Http request to retrieve credentials failed"); + return AWSError<CoreErrors>(CoreErrors::NETWORK_CONNECTION, true); // Retryable + } + else if (m_errorMarshaller) + { + return m_errorMarshaller->Marshall(*response); + } + else + { + const auto responseCode = response->GetResponseCode(); + + AWS_LOGSTREAM_ERROR(m_logtag.c_str(), "Http request to retrieve credentials failed with error code " + << static_cast<int>(responseCode)); + return CoreErrorsMapper::GetErrorForHttpResponseCode(responseCode); + } + }(); + + if (!m_retryStrategy->ShouldRetry(error, retries)) + { + AWS_LOGSTREAM_ERROR(m_logtag.c_str(), "Can not retrive resource from " << httpRequest->GetURIString()); + return {{}, response->GetHeaders(), error.GetResponseCode()}; + } + auto sleepMillis = m_retryStrategy->CalculateDelayBeforeNextRetry(error, retries); + AWS_LOGSTREAM_WARN(m_logtag.c_str(), "Request failed, now waiting " << sleepMillis << " ms before attempting again."); + m_httpClient->RetryRequestSleep(std::chrono::milliseconds(sleepMillis)); + } + } + + EC2MetadataClient::EC2MetadataClient(const char* endpoint) + : AWSHttpResourceClient(EC2_METADATA_CLIENT_LOG_TAG), m_endpoint(endpoint), m_tokenRequired(true) + { + } + + EC2MetadataClient::EC2MetadataClient(const Aws::Client::ClientConfiguration &clientConfiguration, const char *endpoint) + : AWSHttpResourceClient(clientConfiguration, EC2_METADATA_CLIENT_LOG_TAG), m_endpoint(endpoint), m_tokenRequired(true) + { + } + + EC2MetadataClient::~EC2MetadataClient() + { + + } + + Aws::String EC2MetadataClient::GetResource(const char* resourcePath) const + { + return GetResource(m_endpoint.c_str(), resourcePath, nullptr/*authToken*/); + } + + Aws::String EC2MetadataClient::GetDefaultCredentials() const + { + std::unique_lock<std::recursive_mutex> locker(m_tokenMutex); + if (m_tokenRequired) + { + return GetDefaultCredentialsSecurely(); + } + + AWS_LOGSTREAM_TRACE(m_logtag.c_str(), "Getting default credentials for ec2 instance"); + auto result = GetResourceWithAWSWebServiceResult(m_endpoint.c_str(), EC2_SECURITY_CREDENTIALS_RESOURCE, nullptr); + Aws::String credentialsString = result.GetPayload(); + auto httpResponseCode = result.GetResponseCode(); + + // Note, if service is insane, it might return 404 for our initial secure call, + // then when we fall back to insecure call, it might return 401 ask for secure call, + // Then, SDK might get into a recursive loop call situation between secure and insecure call. + if (httpResponseCode == Http::HttpResponseCode::UNAUTHORIZED) + { + m_tokenRequired = true; + return {}; + } + locker.unlock(); + + Aws::String trimmedCredentialsString = StringUtils::Trim(credentialsString.c_str()); + if (trimmedCredentialsString.empty()) return {}; + + Aws::Vector<Aws::String> securityCredentials = StringUtils::Split(trimmedCredentialsString, '\n'); + + AWS_LOGSTREAM_DEBUG(m_logtag.c_str(), "Calling EC2MetadataService resource, " << EC2_SECURITY_CREDENTIALS_RESOURCE + << " returned credential string " << trimmedCredentialsString); + + if (securityCredentials.size() == 0) + { + AWS_LOGSTREAM_WARN(m_logtag.c_str(), "Initial call to ec2Metadataservice to get credentials failed"); + return {}; + } + + Aws::StringStream ss; + ss << EC2_SECURITY_CREDENTIALS_RESOURCE << "/" << securityCredentials[0]; + AWS_LOGSTREAM_DEBUG(m_logtag.c_str(), "Calling EC2MetadataService resource " << ss.str()); + return GetResource(ss.str().c_str()); + } + + Aws::String EC2MetadataClient::GetDefaultCredentialsSecurely() const + { + std::unique_lock<std::recursive_mutex> locker(m_tokenMutex); + if (!m_tokenRequired) + { + return GetDefaultCredentials(); + } + + Aws::StringStream ss; + ss << m_endpoint << EC2_IMDS_TOKEN_RESOURCE; + std::shared_ptr<HttpRequest> tokenRequest(CreateHttpRequest(ss.str(), HttpMethod::HTTP_PUT, + Aws::Utils::Stream::DefaultResponseStreamFactoryMethod)); + tokenRequest->SetHeaderValue(EC2_IMDS_TOKEN_TTL_HEADER, EC2_IMDS_TOKEN_TTL_DEFAULT_VALUE); + auto userAgentString = ComputeUserAgentString(); + tokenRequest->SetUserAgent(userAgentString); + AWS_LOGSTREAM_TRACE(m_logtag.c_str(), "Calling EC2MetadataService to get token"); + auto result = GetResourceWithAWSWebServiceResult(tokenRequest); + Aws::String tokenString = result.GetPayload(); + Aws::String trimmedTokenString = StringUtils::Trim(tokenString.c_str()); + + if (result.GetResponseCode() == HttpResponseCode::BAD_REQUEST) + { + return {}; + } + else if (result.GetResponseCode() != HttpResponseCode::OK || trimmedTokenString.empty()) + { + m_tokenRequired = false; + AWS_LOGSTREAM_TRACE(m_logtag.c_str(), "Calling EC2MetadataService to get token failed, falling back to less secure way."); + return GetDefaultCredentials(); + } + m_token = trimmedTokenString; + locker.unlock(); + ss.str(""); + ss << m_endpoint << EC2_SECURITY_CREDENTIALS_RESOURCE; + std::shared_ptr<HttpRequest> profileRequest(CreateHttpRequest(ss.str(), HttpMethod::HTTP_GET, + Aws::Utils::Stream::DefaultResponseStreamFactoryMethod)); + profileRequest->SetHeaderValue(EC2_IMDS_TOKEN_HEADER, trimmedTokenString); + profileRequest->SetUserAgent(userAgentString); + Aws::String profileString = GetResourceWithAWSWebServiceResult(profileRequest).GetPayload(); + + Aws::String trimmedProfileString = StringUtils::Trim(profileString.c_str()); + Aws::Vector<Aws::String> securityCredentials = StringUtils::Split(trimmedProfileString, '\n'); + + AWS_LOGSTREAM_DEBUG(m_logtag.c_str(), "Calling EC2MetadataService resource, " << EC2_SECURITY_CREDENTIALS_RESOURCE + << " with token returned profile string " << trimmedProfileString); + if (securityCredentials.size() == 0) + { + AWS_LOGSTREAM_WARN(m_logtag.c_str(), "Calling EC2Metadataservice to get profiles failed"); + return {}; + } + + ss.str(""); + ss << m_endpoint << EC2_SECURITY_CREDENTIALS_RESOURCE << "/" << securityCredentials[0]; + std::shared_ptr<HttpRequest> credentialsRequest(CreateHttpRequest(ss.str(), HttpMethod::HTTP_GET, + Aws::Utils::Stream::DefaultResponseStreamFactoryMethod)); + credentialsRequest->SetHeaderValue(EC2_IMDS_TOKEN_HEADER, trimmedTokenString); + credentialsRequest->SetUserAgent(userAgentString); + AWS_LOGSTREAM_DEBUG(m_logtag.c_str(), "Calling EC2MetadataService resource " << ss.str() << " with token."); + return GetResourceWithAWSWebServiceResult(credentialsRequest).GetPayload(); + } + + Aws::String EC2MetadataClient::GetCurrentRegion() const + { + if (!m_region.empty()) + { + return m_region; + } + + AWS_LOGSTREAM_TRACE(m_logtag.c_str(), "Getting current region for ec2 instance"); + + Aws::StringStream ss; + ss << m_endpoint << EC2_REGION_RESOURCE; + std::shared_ptr<HttpRequest> regionRequest(CreateHttpRequest(ss.str(), HttpMethod::HTTP_GET, + Aws::Utils::Stream::DefaultResponseStreamFactoryMethod)); + { + std::lock_guard<std::recursive_mutex> locker(m_tokenMutex); + if (m_tokenRequired) + { + regionRequest->SetHeaderValue(EC2_IMDS_TOKEN_HEADER, m_token); + } + } + regionRequest->SetUserAgent(ComputeUserAgentString()); + Aws::String azString = GetResourceWithAWSWebServiceResult(regionRequest).GetPayload(); + + if (azString.empty()) + { + AWS_LOGSTREAM_INFO(m_logtag.c_str() , + "Unable to pull region from instance metadata service "); + return {}; + } + + Aws::String trimmedAZString = StringUtils::Trim(azString.c_str()); + AWS_LOGSTREAM_DEBUG(m_logtag.c_str(), "Calling EC2MetadataService resource " + << EC2_REGION_RESOURCE << " , returned credential string " << trimmedAZString); + + Aws::String region; + region.reserve(trimmedAZString.length()); + + bool digitFound = false; + for (auto character : trimmedAZString) + { + if(digitFound && !isdigit(character)) + { + break; + } + if (isdigit(character)) + { + digitFound = true; + } + + region.append(1, character); + } + + AWS_LOGSTREAM_INFO(m_logtag.c_str(), "Detected current region as " << region); + m_region = region; + return region; + } + + #ifdef _MSC_VER + // VS2015 compiler's bug, warning s_ec2metadataClient: symbol will be dynamically initialized (implementation limitation) + AWS_SUPPRESS_WARNING(4592, + static std::shared_ptr<EC2MetadataClient> s_ec2metadataClient(nullptr); + ) + #else + static std::shared_ptr<EC2MetadataClient> s_ec2metadataClient(nullptr); + #endif + + void InitEC2MetadataClient() + { + if (s_ec2metadataClient) + { + return; + } + s_ec2metadataClient = Aws::MakeShared<EC2MetadataClient>(EC2_METADATA_CLIENT_LOG_TAG); + } + + void CleanupEC2MetadataClient() + { + if (!s_ec2metadataClient) + { + return; + } + s_ec2metadataClient = nullptr; + } + + std::shared_ptr<EC2MetadataClient> GetEC2MetadataClient() + { + return s_ec2metadataClient; + } + + + ECSCredentialsClient::ECSCredentialsClient(const char* resourcePath, const char* endpoint, const char* token) + : AWSHttpResourceClient(ECS_CREDENTIALS_CLIENT_LOG_TAG), + m_resourcePath(resourcePath), m_endpoint(endpoint), m_token(token) + { + } + + ECSCredentialsClient::ECSCredentialsClient(const Aws::Client::ClientConfiguration& clientConfiguration, const char* resourcePath, const char* endpoint, const char* token) + : AWSHttpResourceClient(clientConfiguration, ECS_CREDENTIALS_CLIENT_LOG_TAG), + m_resourcePath(resourcePath), m_endpoint(endpoint), m_token(token) + { + } + + static const char STS_RESOURCE_CLIENT_LOG_TAG[] = "STSResourceClient"; + STSCredentialsClient::STSCredentialsClient(const Aws::Client::ClientConfiguration& clientConfiguration) + : AWSHttpResourceClient(clientConfiguration, STS_RESOURCE_CLIENT_LOG_TAG) + { + SetErrorMarshaller(Aws::MakeUnique<Aws::Client::XmlErrorMarshaller>(STS_RESOURCE_CLIENT_LOG_TAG)); + + Aws::StringStream ss; + if (clientConfiguration.scheme == Aws::Http::Scheme::HTTP) + { + ss << "http://"; + } + else + { + ss << "https://"; + } + + static const int CN_NORTH_1_HASH = Aws::Utils::HashingUtils::HashString(Aws::Region::CN_NORTH_1); + static const int CN_NORTHWEST_1_HASH = Aws::Utils::HashingUtils::HashString(Aws::Region::CN_NORTHWEST_1); + auto hash = Aws::Utils::HashingUtils::HashString(clientConfiguration.region.c_str()); + + ss << "sts." << clientConfiguration.region << ".amazonaws.com"; + if (hash == CN_NORTH_1_HASH || hash == CN_NORTHWEST_1_HASH) + { + ss << ".cn"; + } + m_endpoint = ss.str(); + + AWS_LOGSTREAM_INFO(STS_RESOURCE_CLIENT_LOG_TAG, "Creating STS ResourceClient with endpoint: " << m_endpoint); + } + + STSCredentialsClient::STSAssumeRoleWithWebIdentityResult STSCredentialsClient::GetAssumeRoleWithWebIdentityCredentials(const STSAssumeRoleWithWebIdentityRequest& request) + { + //Calculate query string + Aws::StringStream ss; + ss << "Action=AssumeRoleWithWebIdentity" + << "&Version=2011-06-15" + << "&RoleSessionName=" << Aws::Utils::StringUtils::URLEncode(request.roleSessionName.c_str()) + << "&RoleArn=" << Aws::Utils::StringUtils::URLEncode(request.roleArn.c_str()) + << "&WebIdentityToken=" << Aws::Utils::StringUtils::URLEncode(request.webIdentityToken.c_str()); + + std::shared_ptr<HttpRequest> httpRequest(CreateHttpRequest(m_endpoint, HttpMethod::HTTP_POST, + Aws::Utils::Stream::DefaultResponseStreamFactoryMethod)); + + httpRequest->SetUserAgent(ComputeUserAgentString()); + + std::shared_ptr<Aws::IOStream> body = Aws::MakeShared<Aws::StringStream>("STS_RESOURCE_CLIENT_LOG_TAG"); + *body << ss.str(); + + httpRequest->AddContentBody(body); + body->seekg(0, body->end); + auto streamSize = body->tellg(); + body->seekg(0, body->beg); + Aws::StringStream contentLength; + contentLength << streamSize; + httpRequest->SetContentLength(contentLength.str()); + httpRequest->SetContentType("application/x-www-form-urlencoded"); + + Aws::String credentialsStr = GetResourceWithAWSWebServiceResult(httpRequest).GetPayload(); + + //Parse credentials + STSAssumeRoleWithWebIdentityResult result; + if (credentialsStr.empty()) + { + AWS_LOGSTREAM_WARN(STS_RESOURCE_CLIENT_LOG_TAG, "Get an empty credential from sts"); + return result; + } + + const Utils::Xml::XmlDocument xmlDocument = XmlDocument::CreateFromXmlString(credentialsStr); + XmlNode rootNode = xmlDocument.GetRootElement(); + XmlNode resultNode = rootNode; + if (!rootNode.IsNull() && (rootNode.GetName() != "AssumeRoleWithWebIdentityResult")) + { + resultNode = rootNode.FirstChild("AssumeRoleWithWebIdentityResult"); + } + + if (!resultNode.IsNull()) + { + XmlNode credentialsNode = resultNode.FirstChild("Credentials"); + if (!credentialsNode.IsNull()) + { + XmlNode accessKeyIdNode = credentialsNode.FirstChild("AccessKeyId"); + if (!accessKeyIdNode.IsNull()) + { + result.creds.SetAWSAccessKeyId(accessKeyIdNode.GetText()); + } + + XmlNode secretAccessKeyNode = credentialsNode.FirstChild("SecretAccessKey"); + if (!secretAccessKeyNode.IsNull()) + { + result.creds.SetAWSSecretKey(secretAccessKeyNode.GetText()); + } + + XmlNode sessionTokenNode = credentialsNode.FirstChild("SessionToken"); + if (!sessionTokenNode.IsNull()) + { + result.creds.SetSessionToken(sessionTokenNode.GetText()); + } + + XmlNode expirationNode = credentialsNode.FirstChild("Expiration"); + if (!expirationNode.IsNull()) + { + result.creds.SetExpiration(DateTime(StringUtils::Trim(expirationNode.GetText().c_str()).c_str(), DateFormat::ISO_8601)); + } + } + } + return result; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/monitoring/DefaultMonitoring.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/monitoring/DefaultMonitoring.cpp new file mode 100644 index 0000000000..9953004bc3 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/monitoring/DefaultMonitoring.cpp @@ -0,0 +1,340 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/memory/AWSMemory.h> +#include <aws/core/monitoring/DefaultMonitoring.h> +#include <aws/core/utils/DateTime.h> +#include <aws/core/utils/json/JsonSerializer.h> +#include <aws/core/utils/Outcome.h> +#include <aws/core/client/AWSClient.h> +#include <aws/core/auth/AWSCredentialsProvider.h> +#include <aws/core/platform/Environment.h> +#include <aws/core/config/AWSProfileConfigLoader.h> +#include <aws/core/utils/logging/LogMacros.h> +using namespace Aws::Utils; + +namespace Aws +{ + namespace Monitoring + { + static const char DEFAULT_MONITORING_ALLOC_TAG[] = "DefaultMonitoringAllocTag"; + static const int CLIENT_ID_LENGTH_LIMIT = 256; + static const int USER_AGENT_LENGTH_LIMIT = 256; + static const int ERROR_MESSAGE_LENGTH_LIMIT = 512; + + const char DEFAULT_MONITORING_CLIENT_ID[] = ""; // default to empty; + const char DEFAULT_MONITORING_HOST[] = "127.0.0.1"; // default to loopback ip address instead of "localhost" based on design specification. + unsigned short DEFAULT_MONITORING_PORT = 31000; //default to 31000; + bool DEFAULT_MONITORING_ENABLE = false; //default to false; + + const int DefaultMonitoring::DEFAULT_MONITORING_VERSION = 1; + const char DefaultMonitoring::DEFAULT_CSM_CONFIG_ENABLED[] = "csm_enabled"; + const char DefaultMonitoring::DEFAULT_CSM_CONFIG_CLIENT_ID[] = "csm_client_id"; + const char DefaultMonitoring::DEFAULT_CSM_CONFIG_HOST[] = "csm_host"; + const char DefaultMonitoring::DEFAULT_CSM_CONFIG_PORT[] = "csm_port"; + const char DefaultMonitoring::DEFAULT_CSM_ENVIRONMENT_VAR_ENABLED[] = "AWS_CSM_ENABLED"; + const char DefaultMonitoring::DEFAULT_CSM_ENVIRONMENT_VAR_CLIENT_ID[] = "AWS_CSM_CLIENT_ID"; + const char DefaultMonitoring::DEFAULT_CSM_ENVIRONMENT_VAR_HOST[] = "AWS_CSM_HOST"; + const char DefaultMonitoring::DEFAULT_CSM_ENVIRONMENT_VAR_PORT[] = "AWS_CSM_PORT"; + + + struct DefaultContext + { + Aws::Utils::DateTime apiCallStartTime; + Aws::Utils::DateTime attemptStartTime; + int retryCount = 0; + bool lastAttemptSucceeded = false; + bool lastErrorRetryable = false; //doesn't apply if last attempt succeeded. + const Aws::Client::HttpResponseOutcome* outcome = nullptr; + }; + + static inline void FillRequiredFieldsToJson(Json::JsonValue& json, + const Aws::String& type, + const Aws::String& service, + const Aws::String& api, + const Aws::String& clientId, + const DateTime& timestamp, + int version, + const Aws::String& userAgent) + { + json.WithString("Type", type) + .WithString("Service", service) + .WithString("Api", api) + .WithString("ClientId", clientId.substr(0, CLIENT_ID_LENGTH_LIMIT)) + .WithInt64("Timestamp", timestamp.Millis()) + .WithInteger("Version", version) + .WithString("UserAgent", userAgent.substr(0, USER_AGENT_LENGTH_LIMIT)); + } + + static inline void FillRequiredApiCallFieldsToJson(Json::JsonValue& json, + int attemptCount, + int64_t apiCallLatency, + bool maxRetriesExceeded) + { + json.WithInteger("AttemptCount", attemptCount) + .WithInt64("Latency", apiCallLatency) + .WithInteger("MaxRetriesExceeded", maxRetriesExceeded ? 1 : 0); + } + + static inline void FillRequiredApiAttemptFieldsToJson(Json::JsonValue& json, + const Aws::String& domainName, + int64_t attemptLatency) + { + json.WithString("Fqdn", domainName) + .WithInt64("AttemptLatency", attemptLatency); + } + + static inline void ExportResponseHeaderToJson(Json::JsonValue& json, const Aws::Http::HeaderValueCollection& headers, + const Aws::String& headerName, const Aws::String& targetName) + { + auto iter = headers.find(headerName); + if (iter != headers.end()) + { + json.WithString(targetName, iter->second); + } + } + + static inline void ExportHttpMetricsToJson(Json::JsonValue& json, const Aws::Monitoring::HttpClientMetricsCollection& httpMetrics, Aws::Monitoring::HttpClientMetricsType type) + { + auto iter = httpMetrics.find(GetHttpClientMetricNameByType(type)); + if (iter != httpMetrics.end()) + { + json.WithInt64(GetHttpClientMetricNameByType(type), iter->second); + } + } + + static inline void FillOptionalApiCallFieldsToJson(Json::JsonValue& json, + const Aws::Http::HttpRequest* request, + const Aws::Client::HttpResponseOutcome& outcome) + { + if (!request->GetSigningRegion().empty()) + { + json.WithString("Region", request->GetSigningRegion()); + } + if (!outcome.IsSuccess()) + { + if (outcome.GetError().GetExceptionName().empty()) // Not Aws Exception + { + json.WithString("FinalSdkExceptionMessage", outcome.GetError().GetMessage().substr(0, ERROR_MESSAGE_LENGTH_LIMIT)); + } + else // Aws Exception + { + json.WithString("FinalAwsException", outcome.GetError().GetExceptionName()) + .WithString("FinalAwsExceptionMessage", outcome.GetError().GetMessage().substr(0, ERROR_MESSAGE_LENGTH_LIMIT)); + } + json.WithInteger("FinalHttpStatusCode", static_cast<int>(outcome.GetError().GetResponseCode())); + } + else + { + json.WithInteger("FinalHttpStatusCode", static_cast<int>(outcome.GetResult()->GetResponseCode())); + } + } + + static inline void FillOptionalApiAttemptFieldsToJson(Json::JsonValue& json, + const Aws::Http::HttpRequest* request, + const Aws::Client::HttpResponseOutcome& outcome, + const CoreMetricsCollection& metricsFromCore) + { + /** + *No matter request succeeded or not, these fields should be included as long as their requirements + *are met. We should be able to access response (so as to access original request) if the response has error. + */ + if (request->HasAwsSessionToken() && !request->GetAwsSessionToken().empty()) + { + json.WithString("SessionToken", request->GetAwsSessionToken()); + } + if (!request->GetSigningRegion().empty()) + { + json.WithString("Region", request->GetSigningRegion()); + } + if (!request->GetSigningAccessKey().empty()) + { + json.WithString("AccessKey", request->GetSigningAccessKey()); + } + + const auto& headers = outcome.IsSuccess() ? outcome.GetResult()->GetHeaders() : outcome.GetError().GetResponseHeaders(); + + ExportResponseHeaderToJson(json, headers, StringUtils::ToLower("x-amzn-RequestId"), "XAmznRequestId"); + ExportResponseHeaderToJson(json, headers, StringUtils::ToLower("x-amz-request-id"), "XAmzRequestId"); + ExportResponseHeaderToJson(json, headers, StringUtils::ToLower("x-amz-id-2"), "XAmzId2"); + + if (!outcome.IsSuccess()) + { + if (outcome.GetError().GetExceptionName().empty()) // Not Aws Exception + { + json.WithString("SdkExceptionMessage", outcome.GetError().GetMessage().substr(0, ERROR_MESSAGE_LENGTH_LIMIT)); + } + else // Aws Exception + { + json.WithString("AwsException", outcome.GetError().GetExceptionName()) + .WithString("AwsExceptionMessage", outcome.GetError().GetMessage().substr(0, ERROR_MESSAGE_LENGTH_LIMIT)); + } + json.WithInteger("HttpStatusCode", static_cast<int>(outcome.GetError().GetResponseCode())); + } + else + { + json.WithInteger("HttpStatusCode", static_cast<int>(outcome.GetResult()->GetResponseCode())); + } + + // Optional MetricsCollectedFromCore + ExportHttpMetricsToJson(json, metricsFromCore.httpClientMetrics, HttpClientMetricsType::AcquireConnectionLatency); + ExportHttpMetricsToJson(json, metricsFromCore.httpClientMetrics, HttpClientMetricsType::ConnectionReused); + ExportHttpMetricsToJson(json, metricsFromCore.httpClientMetrics, HttpClientMetricsType::ConnectLatency); + ExportHttpMetricsToJson(json, metricsFromCore.httpClientMetrics, HttpClientMetricsType::DestinationIp); + ExportHttpMetricsToJson(json, metricsFromCore.httpClientMetrics, HttpClientMetricsType::DnsLatency); + ExportHttpMetricsToJson(json, metricsFromCore.httpClientMetrics, HttpClientMetricsType::RequestLatency); + ExportHttpMetricsToJson(json, metricsFromCore.httpClientMetrics, HttpClientMetricsType::SslLatency); + ExportHttpMetricsToJson(json, metricsFromCore.httpClientMetrics, HttpClientMetricsType::TcpLatency); + } + + DefaultMonitoring::DefaultMonitoring(const Aws::String& clientId, const Aws::String& host, unsigned short port): + m_udp(host.c_str(), port), m_clientId(clientId) + { + } + + void* DefaultMonitoring::OnRequestStarted(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request) const + { + AWS_UNREFERENCED_PARAM(request); + + AWS_LOGSTREAM_DEBUG(DEFAULT_MONITORING_ALLOC_TAG, "OnRequestStart Service: " << serviceName << "Request: " << requestName); + auto context = Aws::New<DefaultContext>(DEFAULT_MONITORING_ALLOC_TAG); + context->apiCallStartTime = Aws::Utils::DateTime::Now(); + context->attemptStartTime = context->apiCallStartTime; + context->retryCount = 0; + return context; + } + + + void DefaultMonitoring::OnRequestSucceeded(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request, + const Aws::Client::HttpResponseOutcome& outcome, const CoreMetricsCollection& metricsFromCore, void* context) const + { + AWS_LOGSTREAM_DEBUG(DEFAULT_MONITORING_ALLOC_TAG, "OnRequestSucceeded Service: " << serviceName << "Request: " << requestName); + CollectAndSendAttemptData(serviceName, requestName, request, outcome, metricsFromCore, context); + } + + void DefaultMonitoring::OnRequestFailed(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request, + const Aws::Client::HttpResponseOutcome& outcome, const CoreMetricsCollection& metricsFromCore, void* context) const + { + AWS_LOGSTREAM_DEBUG(DEFAULT_MONITORING_ALLOC_TAG, "OnRequestFailed Service: " << serviceName << "Request: " << requestName); + CollectAndSendAttemptData(serviceName, requestName, request, outcome, metricsFromCore, context); + } + + void DefaultMonitoring::OnRequestRetry(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr<const Aws::Http::HttpRequest>& request, void* context) const + { + AWS_UNREFERENCED_PARAM(request); + + DefaultContext* defaultContext = static_cast<DefaultContext*>(context); + defaultContext->retryCount++; + defaultContext->attemptStartTime = Aws::Utils::DateTime::Now(); + AWS_LOGSTREAM_DEBUG(DEFAULT_MONITORING_ALLOC_TAG, "OnRequestRetry Service: " << serviceName << "Request: " << requestName << " RetryCnt:" << defaultContext->retryCount); + } + + void DefaultMonitoring::OnFinish(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr<const Aws::Http::HttpRequest>& request, void* context) const + { + AWS_UNREFERENCED_PARAM(request); + AWS_LOGSTREAM_DEBUG(DEFAULT_MONITORING_ALLOC_TAG, "OnRequestFinish Service: " << serviceName << "Request: " << requestName); + + DefaultContext* defaultContext = static_cast<DefaultContext*>(context); + Aws::Utils::Json::JsonValue json; + FillRequiredFieldsToJson(json, "ApiCall", serviceName, requestName, m_clientId, defaultContext->apiCallStartTime, DEFAULT_MONITORING_VERSION, request->GetUserAgent()); + FillRequiredApiCallFieldsToJson(json, defaultContext->retryCount + 1, (DateTime::Now() - defaultContext->apiCallStartTime).count(), (!defaultContext->lastAttemptSucceeded && defaultContext->lastErrorRetryable)); + FillOptionalApiCallFieldsToJson(json, request.get(), *(defaultContext->outcome)); + Aws::String compactData = json.View().WriteCompact(); + m_udp.SendData(reinterpret_cast<const uint8_t*>(compactData.c_str()), static_cast<int>(compactData.size())); + AWS_LOGSTREAM_DEBUG(DEFAULT_MONITORING_ALLOC_TAG, "Send API Metrics: \n" << json.View().WriteReadable()); + Aws::Delete(defaultContext); + } + + void DefaultMonitoring::CollectAndSendAttemptData(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr<const Aws::Http::HttpRequest>& request, const Aws::Client::HttpResponseOutcome& outcome, + const CoreMetricsCollection& metricsFromCore, void* context) const + { + DefaultContext* defaultContext = static_cast<DefaultContext*>(context); + defaultContext->outcome = &outcome; + defaultContext->lastAttemptSucceeded = outcome.IsSuccess() ? true : false; + defaultContext->lastErrorRetryable = (!outcome.IsSuccess() && outcome.GetError().ShouldRetry()) ? true : false; + Aws::Utils::Json::JsonValue json; + FillRequiredFieldsToJson(json, "ApiCallAttempt", serviceName, requestName, m_clientId, defaultContext->attemptStartTime, DEFAULT_MONITORING_VERSION, request->GetUserAgent()); + FillRequiredApiAttemptFieldsToJson(json, request->GetUri().GetAuthority(), (DateTime::Now() - defaultContext->attemptStartTime).count()); + FillOptionalApiAttemptFieldsToJson(json, request.get(), outcome, metricsFromCore); + Aws::String compactData = json.View().WriteCompact(); + AWS_LOGSTREAM_DEBUG(DEFAULT_MONITORING_ALLOC_TAG, "Send Attempt Metrics: \n" << json.View().WriteReadable()); + m_udp.SendData(reinterpret_cast<const uint8_t*>(compactData.c_str()), static_cast<int>(compactData.size())); + } + + Aws::UniquePtr<MonitoringInterface> DefaultMonitoringFactory::CreateMonitoringInstance() const + { + Aws::String clientId(DEFAULT_MONITORING_CLIENT_ID); // default to empty + Aws::String host(DEFAULT_MONITORING_HOST); // default to 127.0.0.1 + unsigned short port = DEFAULT_MONITORING_PORT; // default to 31000 + bool enable = DEFAULT_MONITORING_ENABLE; //default to false; + + //check profile_config + Aws::String tmpEnable = Aws::Config::GetCachedConfigValue(DefaultMonitoring::DEFAULT_CSM_CONFIG_ENABLED); + Aws::String tmpClientId = Aws::Config::GetCachedConfigValue(DefaultMonitoring::DEFAULT_CSM_CONFIG_CLIENT_ID); + Aws::String tmpHost = Aws::Config::GetCachedConfigValue(DefaultMonitoring::DEFAULT_CSM_CONFIG_HOST); + Aws::String tmpPort = Aws::Config::GetCachedConfigValue(DefaultMonitoring::DEFAULT_CSM_CONFIG_PORT); + + if (!tmpEnable.empty()) + { + enable = StringUtils::CaselessCompare(tmpEnable.c_str(), "true") ? true : false; + AWS_LOGSTREAM_DEBUG(DEFAULT_MONITORING_ALLOC_TAG, "Resolved csm_enabled from profile_config to be " << enable); + } + if (!tmpClientId.empty()) + { + clientId = tmpClientId; + AWS_LOGSTREAM_DEBUG(DEFAULT_MONITORING_ALLOC_TAG, "Resolved csm_client_id from profile_config to be " << clientId); + } + + if (!tmpHost.empty()) + { + host = tmpHost; + AWS_LOGSTREAM_DEBUG(DEFAULT_MONITORING_ALLOC_TAG, "Resolved csm_host from profile_config to be " << host); + } + + if (!tmpPort.empty()) + { + port = static_cast<short>(StringUtils::ConvertToInt32(tmpPort.c_str())); + AWS_LOGSTREAM_DEBUG(DEFAULT_MONITORING_ALLOC_TAG, "Resolved csm_port from profile_config to be " << port); + } + + // check environment variables + tmpEnable = Aws::Environment::GetEnv(DefaultMonitoring::DEFAULT_CSM_ENVIRONMENT_VAR_ENABLED); + tmpClientId = Aws::Environment::GetEnv(DefaultMonitoring::DEFAULT_CSM_ENVIRONMENT_VAR_CLIENT_ID); + tmpHost = Aws::Environment::GetEnv(DefaultMonitoring::DEFAULT_CSM_ENVIRONMENT_VAR_HOST); + tmpPort = Aws::Environment::GetEnv(DefaultMonitoring::DEFAULT_CSM_ENVIRONMENT_VAR_PORT); + if (!tmpEnable.empty()) + { + enable = StringUtils::CaselessCompare(tmpEnable.c_str(), "true") ? true : false; + AWS_LOGSTREAM_DEBUG(DEFAULT_MONITORING_ALLOC_TAG, "Resolved AWS_CSM_ENABLED from Environment variable to be " << enable); + } + if (!tmpClientId.empty()) + { + clientId = tmpClientId; + AWS_LOGSTREAM_DEBUG(DEFAULT_MONITORING_ALLOC_TAG, "Resolved AWS_CSM_CLIENT_ID from Environment variable to be " << clientId); + + } + if (!tmpHost.empty()) + { + host = tmpHost; + AWS_LOGSTREAM_DEBUG(DEFAULT_MONITORING_ALLOC_TAG, "Resolved AWS_CSM_HOST from Environment variable to be " << host); + } + if (!tmpPort.empty()) + { + port = static_cast<unsigned short>(StringUtils::ConvertToInt32(tmpPort.c_str())); + AWS_LOGSTREAM_DEBUG(DEFAULT_MONITORING_ALLOC_TAG, "Resolved AWS_CSM_PORT from Environment variable to be " << port); + } + + if (!enable) + { + return nullptr; + } + return Aws::MakeUnique<DefaultMonitoring>(DEFAULT_MONITORING_ALLOC_TAG, clientId, host, port); + } + + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/monitoring/HttpClientMetrics.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/monitoring/HttpClientMetrics.cpp new file mode 100644 index 0000000000..f3ef582867 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/monitoring/HttpClientMetrics.cpp @@ -0,0 +1,71 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/HashingUtils.h> +#include <aws/core/monitoring/HttpClientMetrics.h> + +namespace Aws +{ + namespace Monitoring + { + static const char HTTP_CLIENT_METRICS_DESTINATION_IP[] = "DestinationIp"; + static const char HTTP_CLIENT_METRICS_ACQUIRE_CONNECTION_LATENCY[] = "AcquireConnectionLatency"; + static const char HTTP_CLIENT_METRICS_CONNECTION_REUSED[] = "ConnectionReused"; + static const char HTTP_CLIENT_METRICS_CONNECTION_LATENCY[] = "ConnectLatency"; + static const char HTTP_CLIENT_METRICS_REQUEST_LATENCY[] = "RequestLatency"; + static const char HTTP_CLIENT_METRICS_DNS_LATENCY[] = "DnsLatency"; + static const char HTTP_CLIENT_METRICS_TCP_LATENCY[] = "TcpLatency"; + static const char HTTP_CLIENT_METRICS_SSL_LATENCY[] = "SslLatency"; + static const char HTTP_CLIENT_METRICS_UNKNOWN[] = "Unknown"; + + using namespace Aws::Utils; + HttpClientMetricsType GetHttpClientMetricTypeByName(const Aws::String& name) + { + static std::map<int, HttpClientMetricsType> metricsNameHashToType = + { + std::pair<int, HttpClientMetricsType>(HashingUtils::HashString(HTTP_CLIENT_METRICS_DESTINATION_IP), HttpClientMetricsType::DestinationIp), + std::pair<int, HttpClientMetricsType>(HashingUtils::HashString(HTTP_CLIENT_METRICS_ACQUIRE_CONNECTION_LATENCY), HttpClientMetricsType::AcquireConnectionLatency), + std::pair<int, HttpClientMetricsType>(HashingUtils::HashString(HTTP_CLIENT_METRICS_CONNECTION_REUSED), HttpClientMetricsType::ConnectionReused), + std::pair<int, HttpClientMetricsType>(HashingUtils::HashString(HTTP_CLIENT_METRICS_CONNECTION_LATENCY), HttpClientMetricsType::ConnectLatency), + std::pair<int, HttpClientMetricsType>(HashingUtils::HashString(HTTP_CLIENT_METRICS_REQUEST_LATENCY), HttpClientMetricsType::RequestLatency), + std::pair<int, HttpClientMetricsType>(HashingUtils::HashString(HTTP_CLIENT_METRICS_DNS_LATENCY), HttpClientMetricsType::DnsLatency), + std::pair<int, HttpClientMetricsType>(HashingUtils::HashString(HTTP_CLIENT_METRICS_TCP_LATENCY), HttpClientMetricsType::TcpLatency), + std::pair<int, HttpClientMetricsType>(HashingUtils::HashString(HTTP_CLIENT_METRICS_SSL_LATENCY), HttpClientMetricsType::SslLatency) + }; + + int nameHash = HashingUtils::HashString(name.c_str()); + auto it = metricsNameHashToType.find(nameHash); + if (it == metricsNameHashToType.end()) + { + return HttpClientMetricsType::Unknown; + } + return it->second; + } + + Aws::String GetHttpClientMetricNameByType(HttpClientMetricsType type) + { + static std::map<int, std::string> metricsTypeToName = + { + std::pair<int, std::string>(static_cast<int>(HttpClientMetricsType::DestinationIp), HTTP_CLIENT_METRICS_DESTINATION_IP), + std::pair<int, std::string>(static_cast<int>(HttpClientMetricsType::AcquireConnectionLatency), HTTP_CLIENT_METRICS_ACQUIRE_CONNECTION_LATENCY), + std::pair<int, std::string>(static_cast<int>(HttpClientMetricsType::ConnectionReused), HTTP_CLIENT_METRICS_CONNECTION_REUSED), + std::pair<int, std::string>(static_cast<int>(HttpClientMetricsType::ConnectLatency), HTTP_CLIENT_METRICS_CONNECTION_LATENCY), + std::pair<int, std::string>(static_cast<int>(HttpClientMetricsType::RequestLatency), HTTP_CLIENT_METRICS_REQUEST_LATENCY), + std::pair<int, std::string>(static_cast<int>(HttpClientMetricsType::DnsLatency), HTTP_CLIENT_METRICS_DNS_LATENCY), + std::pair<int, std::string>(static_cast<int>(HttpClientMetricsType::TcpLatency), HTTP_CLIENT_METRICS_TCP_LATENCY), + std::pair<int, std::string>(static_cast<int>(HttpClientMetricsType::SslLatency), HTTP_CLIENT_METRICS_SSL_LATENCY), + std::pair<int, std::string>(static_cast<int>(HttpClientMetricsType::Unknown), HTTP_CLIENT_METRICS_UNKNOWN) + }; + + auto it = metricsTypeToName.find(static_cast<int>(type)); + if (it == metricsTypeToName.end()) + { + return HTTP_CLIENT_METRICS_UNKNOWN; + } + return Aws::String(it->second.c_str()); + } + + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/monitoring/MonitoringManager.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/monitoring/MonitoringManager.cpp new file mode 100644 index 0000000000..7a8d3adb41 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/monitoring/MonitoringManager.cpp @@ -0,0 +1,129 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/memory/AWSMemory.h> +#include <aws/core/monitoring/MonitoringInterface.h> +#include <aws/core/monitoring/MonitoringFactory.h> +#include <aws/core/monitoring/MonitoringManager.h> +#include <aws/core/monitoring/DefaultMonitoring.h> +#include <aws/core/Core_EXPORTS.h> + +#ifdef _MSC_VER +#pragma warning(disable : 4592) +#endif + +namespace Aws +{ + namespace Monitoring + { + typedef Aws::Vector<Aws::UniquePtr<MonitoringInterface>> Monitors; + + const char MonitoringTag[] = "MonitoringAllocTag"; + + /** + * Global factory to create global metrics instance. + */ + static Aws::UniquePtr<Monitors> s_monitors; + + Aws::Vector<void*> OnRequestStarted(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request) + { + assert(s_monitors); + Aws::Vector<void*> contexts; + contexts.reserve(s_monitors->size()); + for (const auto& interface: *s_monitors) + { + contexts.emplace_back(interface->OnRequestStarted(serviceName, requestName, request)); + } + return contexts; + } + + void OnRequestSucceeded(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request, + const Aws::Client::HttpResponseOutcome& outcome, const CoreMetricsCollection& metricsFromCore, const Aws::Vector<void*>& contexts) + { + assert(s_monitors); + assert(contexts.size() == s_monitors->size()); + size_t index = 0; + for (const auto& interface: *s_monitors) + { + interface->OnRequestSucceeded(serviceName, requestName, request, outcome, metricsFromCore, contexts[index++]); + } + } + + void OnRequestFailed(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request, + const Aws::Client::HttpResponseOutcome& outcome, const CoreMetricsCollection& metricsFromCore, const Aws::Vector<void*>& contexts) + { + assert(s_monitors); + assert(contexts.size() == s_monitors->size()); + size_t index = 0; + for (const auto& interface: *s_monitors) + { + interface->OnRequestFailed(serviceName, requestName, request, outcome, metricsFromCore, contexts[index++]); + } + } + + void OnRequestRetry(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr<const Aws::Http::HttpRequest>& request, const Aws::Vector<void*>& contexts) + { + assert(s_monitors); + assert(contexts.size() == s_monitors->size()); + size_t index = 0; + for (const auto& interface: *s_monitors) + { + interface->OnRequestRetry(serviceName, requestName, request, contexts[index++]); + } + } + + void OnFinish(const Aws::String& serviceName, const Aws::String& requestName, + const std::shared_ptr<const Aws::Http::HttpRequest>& request, const Aws::Vector<void*>& contexts) + { + assert(s_monitors); + assert(contexts.size() == s_monitors->size()); + size_t index = 0; + for (const auto& interface: *s_monitors) + { + interface->OnFinish(serviceName, requestName, request, contexts[index++]); + } + } + + void InitMonitoring(const std::vector<MonitoringFactoryCreateFunction>& monitoringFactoryCreateFunctions) + { + if (s_monitors) + { + return; + } + s_monitors = Aws::MakeUnique<Monitors>(MonitoringTag); + for (const auto& function: monitoringFactoryCreateFunctions) + { + auto factory = function(); + if (factory) + { + auto instance = factory->CreateMonitoringInstance(); + if (instance) + { + s_monitors->emplace_back(std::move(instance)); + } + } + } + + auto defaultMonitoringFactory = Aws::MakeShared<DefaultMonitoringFactory>(MonitoringTag); + auto instance = defaultMonitoringFactory->CreateMonitoringInstance(); + if (instance) + { + s_monitors->emplace_back(std::move(instance)); + } + } + + void CleanupMonitoring() + { + if (!s_monitors) + { + return; + } + + s_monitors = nullptr; + } + } // namespace Monitoring + +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/net/linux-shared/Net.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/net/linux-shared/Net.cpp new file mode 100644 index 0000000000..244df21945 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/net/linux-shared/Net.cpp @@ -0,0 +1,28 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/net/Net.h> + +namespace Aws +{ + namespace Net + { + // For Posix system, currently we don't need to do anything for network stack initialization. + // But we need to do initialization for WinSock on Windows and call them in Aws.cpp. So these functions + // also exist for Posix systems. + bool IsNetworkInitiated() + { + return true; + } + + void InitNetwork() + { + } + + void CleanupNetwork() + { + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/net/linux-shared/SimpleUDP.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/net/linux-shared/SimpleUDP.cpp new file mode 100644 index 0000000000..d9e0c385fd --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/net/linux-shared/SimpleUDP.cpp @@ -0,0 +1,285 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <unistd.h> +#include <fcntl.h> +#include <cassert> +#include <string.h> +#include <aws/core/net/SimpleUDP.h> +#include <aws/core/utils/logging/LogMacros.h> + +namespace Aws +{ + namespace Net + { + static const char ALLOC_TAG[] = "SimpleUDP"; + static const char IPV4_LOOP_BACK_ADDRESS[] = "127.0.0.1"; + static const char IPV6_LOOP_BACK_ADDRESS[] = "::1"; + + static inline bool IsValidIPAddress(const char* ip, int addressFamily/*AF_INET or AF_INET6*/) + { + char buffer[128]; + return inet_pton(addressFamily, ip, (void*)buffer) == 1 ?true :false; + } + + static bool GetASockAddrFromHostName(const char* hostName, void* sockAddrBuffer, size_t& addrLength, int& addressFamily) + { + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + if (getaddrinfo(hostName, nullptr, &hints, &res)) + { + return false; + } + + memcpy(sockAddrBuffer, res->ai_addr, res->ai_addrlen); + addrLength = res->ai_addrlen; + addressFamily = res->ai_family; + freeaddrinfo(res); + return true; + } + + static sockaddr_in BuildAddrInfoIPV4(const char* hostIP, short port) + { +#if (__GNUC__ == 4) && !defined(__clang__) + AWS_SUPPRESS_WARNING("-Wmissing-field-initializers", + sockaddr_in addrinfo {}; + ); +#else + sockaddr_in addrinfo {}; +#endif + addrinfo.sin_family = AF_INET; + addrinfo.sin_port = htons(port); + inet_pton(AF_INET, hostIP, &addrinfo.sin_addr); + return addrinfo; + } + + static sockaddr_in6 BuildAddrInfoIPV6(const char* hostIP, short port) + { +#if (__GNUC__ == 4) && !defined(__clang__) + AWS_SUPPRESS_WARNING("-Wmissing-field-initializers", + sockaddr_in6 addrinfo {}; + ); +#else + sockaddr_in6 addrinfo {}; +#endif + addrinfo.sin6_family = AF_INET6; + addrinfo.sin6_port = htons(port); + inet_pton(AF_INET6, hostIP, &addrinfo.sin6_addr); + return addrinfo; + } + + SimpleUDP::SimpleUDP(int addressFamily, size_t sendBufSize, size_t receiveBufSize, bool nonBlocking): + m_addressFamily(addressFamily), m_connected(false), m_socket(-1), m_port(0) + { + CreateSocket(addressFamily, sendBufSize, receiveBufSize, nonBlocking); + } + + SimpleUDP::SimpleUDP(bool IPV4, size_t sendBufSize, size_t receiveBufSize, bool nonBlocking) : + m_addressFamily(IPV4 ? AF_INET : AF_INET6), m_connected(false), m_socket(-1), m_port(0) + { + CreateSocket(m_addressFamily, sendBufSize, receiveBufSize, nonBlocking); + } + + SimpleUDP::SimpleUDP(const char* host, unsigned short port, size_t sendBufSize, size_t receiveBufSize, bool nonBlocking) : + m_addressFamily(AF_INET), m_connected(false), m_socket(-1), m_port(port) + { + if (IsValidIPAddress(host, AF_INET)) + { + m_addressFamily = AF_INET; + m_hostIP = Aws::String(host); + } + else if (IsValidIPAddress(host, AF_INET6)) + { + m_addressFamily = AF_INET6; + m_hostIP = Aws::String(host); + } + else + { + char sockAddrBuffer[100]; + char hostBuffer[100]; + size_t addrLength = 0; + if (GetASockAddrFromHostName(host, (void*)sockAddrBuffer, addrLength, m_addressFamily)) + { + if (m_addressFamily == AF_INET) + { + struct sockaddr_in* sockaddr = reinterpret_cast<struct sockaddr_in*>(sockAddrBuffer); + inet_ntop(m_addressFamily, &(sockaddr->sin_addr), hostBuffer, sizeof(hostBuffer)); + } + else + { + struct sockaddr_in6* sockaddr = reinterpret_cast<struct sockaddr_in6*>(sockAddrBuffer); + inet_ntop(m_addressFamily, &(sockaddr->sin6_addr), hostBuffer, sizeof(hostBuffer)); + } + m_hostIP = Aws::String(hostBuffer); + } + else + { + AWS_LOGSTREAM_ERROR(ALLOC_TAG, "Can't retrieve a valid ip address based on provided host: " << host); + } + } + CreateSocket(m_addressFamily, sendBufSize, receiveBufSize, nonBlocking); + } + + SimpleUDP::~SimpleUDP() + { + close(GetUnderlyingSocket()); + } + + void SimpleUDP::CreateSocket(int addressFamily, size_t sendBufSize, size_t receiveBufSize, bool nonBlocking) + { + int sock = socket(addressFamily, SOCK_DGRAM, IPPROTO_UDP); + assert(sock != -1); + + // Try to set sock to nonblocking mode. + if (nonBlocking) + { + int flags = fcntl(sock, F_GETFL, 0); + if (flags != -1) + { + flags |= O_NONBLOCK; + fcntl(sock, F_SETFL, flags); + } + } + + // if sendBufSize is not zero, try to set send buffer size + if (sendBufSize) + { + int ret = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendBufSize, sizeof(sendBufSize)); + if (ret) + { + AWS_LOGSTREAM_WARN(ALLOC_TAG, "Failed to set UDP send buffer size to " << sendBufSize << " for socket " << sock << " error message: " << strerror(errno)); + } + assert(ret == 0); + } + + // if receiveBufSize is not zero, try to set receive buffer size + if (receiveBufSize) + { + int ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &receiveBufSize, sizeof(receiveBufSize)); + if (ret) + { + AWS_LOGSTREAM_WARN(ALLOC_TAG, "Failed to set UDP receive buffer size to " << receiveBufSize << " for socket " << sock << " error message: " << strerror(errno)); + } + assert(ret == 0); + } + + SetUnderlyingSocket(sock); + } + + int SimpleUDP::Connect(const sockaddr* address, size_t addressLength) + { + int ret = connect(GetUnderlyingSocket(), address, static_cast<socklen_t>(addressLength)); + m_connected = ret ? false : true; + return ret; + } + + int SimpleUDP::ConnectToHost(const char* hostIP, unsigned short port) const + { + int ret; + if (m_addressFamily == AF_INET6) + { + sockaddr_in6 addrinfo = BuildAddrInfoIPV6(hostIP, port); + ret = connect(GetUnderlyingSocket(), reinterpret_cast<sockaddr*>(&addrinfo), sizeof(sockaddr_in6)); + } + else + { + sockaddr_in addrinfo = BuildAddrInfoIPV4(hostIP, port); + ret = connect(GetUnderlyingSocket(), reinterpret_cast<sockaddr*>(&addrinfo), sizeof(sockaddr_in)); + } + m_connected = ret ? false : true; + return ret; + } + + int SimpleUDP::ConnectToLocalHost(unsigned short port) const + { + if (m_addressFamily == AF_INET6) + { + return ConnectToHost(IPV6_LOOP_BACK_ADDRESS, port); + } + else + { + return ConnectToHost(IPV4_LOOP_BACK_ADDRESS, port); + } + } + + int SimpleUDP::Bind(const sockaddr* address, size_t addressLength) const + { + return bind(GetUnderlyingSocket(), address, static_cast<socklen_t>(addressLength)); + } + + int SimpleUDP::BindToLocalHost(unsigned short port) const + { + if (m_addressFamily == AF_INET6) + { + sockaddr_in6 addrinfo = BuildAddrInfoIPV6(IPV6_LOOP_BACK_ADDRESS, port); + return bind(GetUnderlyingSocket(), reinterpret_cast<sockaddr*>(&addrinfo), sizeof(sockaddr_in6)); + } + else + { + sockaddr_in addrinfo = BuildAddrInfoIPV4(IPV4_LOOP_BACK_ADDRESS, port); + return bind(GetUnderlyingSocket(), reinterpret_cast<sockaddr*>(&addrinfo), sizeof(sockaddr_in)); + } + } + + int SimpleUDP::SendData(const uint8_t* data, size_t dataLen) const + { + if (!m_connected) + { + ConnectToHost(m_hostIP.c_str(), m_port); + } + return send(GetUnderlyingSocket(), data, dataLen, 0); + } + + int SimpleUDP::SendDataTo(const sockaddr* address, size_t addressLength, const uint8_t* data, size_t dataLen) const + { + if (m_connected) + { + return send(GetUnderlyingSocket(), data, dataLen, 0); + } + else + { + return sendto(GetUnderlyingSocket(), data, dataLen, 0, address, static_cast<socklen_t>(addressLength)); + } + } + + int SimpleUDP::SendDataToLocalHost(const uint8_t* data, size_t dataLen, unsigned short port) const + { + if (m_connected) + { + return send(GetUnderlyingSocket(), data, dataLen, 0); + } + else if (m_addressFamily == AF_INET6) + { + sockaddr_in6 addrinfo = BuildAddrInfoIPV6(IPV6_LOOP_BACK_ADDRESS, port); + return sendto(GetUnderlyingSocket(), data, dataLen, 0, reinterpret_cast<sockaddr*>(&addrinfo), sizeof(sockaddr_in6)); + } + else + { + sockaddr_in addrinfo = BuildAddrInfoIPV4(IPV4_LOOP_BACK_ADDRESS, port); + return sendto(GetUnderlyingSocket(), data, dataLen, 0, reinterpret_cast<sockaddr*>(&addrinfo), sizeof(sockaddr_in)); + } + } + + int SimpleUDP::ReceiveData(uint8_t* buffer, size_t bufferLen) const + { + return recv(GetUnderlyingSocket(), buffer, static_cast<int>(bufferLen), 0); + } + + + int SimpleUDP::ReceiveDataFrom(sockaddr* address, size_t* addressLength, uint8_t* buffer, size_t bufferLen) const + { + return recvfrom(GetUnderlyingSocket(), buffer, static_cast<int>(bufferLen), 0, address, reinterpret_cast<socklen_t*>(addressLength)); + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/platform/linux-shared/Environment.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/platform/linux-shared/Environment.cpp new file mode 100644 index 0000000000..ee627340bb --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/platform/linux-shared/Environment.cpp @@ -0,0 +1,23 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/platform/Environment.h> + +//#include <aws/core/utils/memory/stl/AWSStringStream.h> +//#include <sys/utsname.h> + +namespace Aws +{ +namespace Environment +{ + +Aws::String GetEnv(const char* variableName) +{ + auto variableValue = std::getenv(variableName); + return Aws::String( variableValue ? variableValue : "" ); +} + +} // namespace Environment +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/platform/linux-shared/FileSystem.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/platform/linux-shared/FileSystem.cpp new file mode 100644 index 0000000000..c1ad818911 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/platform/linux-shared/FileSystem.cpp @@ -0,0 +1,292 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include <aws/core/platform/FileSystem.h> + +#include <aws/core/platform/Environment.h> +#include <aws/core/platform/Platform.h> +#include <aws/core/utils/DateTime.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/UUID.h> + +#include <unistd.h> +#include <pwd.h> +#include <sys/stat.h> +#include <dirent.h> +#include <errno.h> +#include <climits> + +#include <cassert> +#ifdef __APPLE__ +#include <mach-o/dyld.h> +#endif +namespace Aws +{ +namespace FileSystem +{ + +static const char* FILE_SYSTEM_UTILS_LOG_TAG = "FileSystemUtils"; + + class PosixDirectory : public Directory + { + public: + PosixDirectory(const Aws::String& path, const Aws::String& relativePath) : Directory(path, relativePath), m_dir(nullptr) + { + m_dir = opendir(m_directoryEntry.path.c_str()); + AWS_LOGSTREAM_TRACE(FILE_SYSTEM_UTILS_LOG_TAG, "Entering directory " << m_directoryEntry.path); + + if(m_dir) + { + AWS_LOGSTREAM_TRACE(FILE_SYSTEM_UTILS_LOG_TAG, "Successfully opened directory " << m_directoryEntry.path); + m_directoryEntry.fileType = FileType::Directory; + } + else + { + AWS_LOGSTREAM_ERROR(FILE_SYSTEM_UTILS_LOG_TAG, "Could not load directory " << m_directoryEntry.path << " with error code " << errno); + } + } + + ~PosixDirectory() + { + if (m_dir) + { + closedir(m_dir); + } + } + + operator bool() const override { return m_directoryEntry.operator bool() && m_dir != nullptr; } + + DirectoryEntry Next() override + { + assert(m_dir); + DirectoryEntry entry; + + dirent* dirEntry; + bool invalidEntry(true); + + while(invalidEntry) + { + if ((dirEntry = readdir(m_dir))) + { + Aws::String entryName = dirEntry->d_name; + if(entryName != ".." && entryName != ".") + { + entry = ParseFileInfo(dirEntry, true); + invalidEntry = false; + } + else + { + AWS_LOGSTREAM_DEBUG(FILE_SYSTEM_UTILS_LOG_TAG, "skipping . or .."); + } + } + else + { + break; + } + } + + return entry; + } + + private: + DirectoryEntry ParseFileInfo(dirent* dirEnt, bool computePath) + { + DirectoryEntry entry; + + if(computePath) + { + Aws::StringStream ss; + ss << m_directoryEntry.path << PATH_DELIM << dirEnt->d_name; + entry.path = ss.str(); + + ss.str(""); + if(m_directoryEntry.relativePath.empty()) + { + ss << dirEnt->d_name; + } + else + { + ss << m_directoryEntry.relativePath << PATH_DELIM << dirEnt->d_name; + } + entry.relativePath = ss.str(); + } + else + { + entry.path = m_directoryEntry.path; + entry.relativePath = m_directoryEntry.relativePath; + } + + AWS_LOGSTREAM_TRACE(FILE_SYSTEM_UTILS_LOG_TAG, "Calling stat on path " << entry.path); + + struct stat dirInfo; + if(!lstat(entry.path.c_str(), &dirInfo)) + { + if(S_ISDIR(dirInfo.st_mode)) + { + AWS_LOGSTREAM_DEBUG(FILE_SYSTEM_UTILS_LOG_TAG, "type directory detected"); + entry.fileType = FileType::Directory; + } + else if(S_ISLNK(dirInfo.st_mode)) + { + AWS_LOGSTREAM_DEBUG(FILE_SYSTEM_UTILS_LOG_TAG, "type symlink detected"); + entry.fileType = FileType::Symlink; + } + else if(S_ISREG(dirInfo.st_mode)) + { + AWS_LOGSTREAM_DEBUG(FILE_SYSTEM_UTILS_LOG_TAG, "type file detected"); + entry.fileType = FileType::File; + } + + entry.fileSize = static_cast<int64_t>(dirInfo.st_size); + AWS_LOGSTREAM_DEBUG(FILE_SYSTEM_UTILS_LOG_TAG, "file size detected as " << entry.fileSize); + } + else + { + AWS_LOGSTREAM_ERROR(FILE_SYSTEM_UTILS_LOG_TAG, "Failed to stat file path " << entry.path << " with error code " << errno); + } + + return entry; + } + + DIR* m_dir; + }; + +Aws::String GetHomeDirectory() +{ + static const char* HOME_DIR_ENV_VAR = "HOME"; + + AWS_LOGSTREAM_TRACE(FILE_SYSTEM_UTILS_LOG_TAG, "Checking " << HOME_DIR_ENV_VAR << " for the home directory."); + + Aws::String homeDir = Aws::Environment::GetEnv(HOME_DIR_ENV_VAR); + + AWS_LOGSTREAM_DEBUG(FILE_SYSTEM_UTILS_LOG_TAG, "Environment value for variable " << HOME_DIR_ENV_VAR << " is " << homeDir); + + if(homeDir.empty()) + { + AWS_LOGSTREAM_WARN(FILE_SYSTEM_UTILS_LOG_TAG, "Home dir not stored in environment, trying to fetch manually from the OS."); + + passwd pw; + passwd *p_pw = nullptr; + char pw_buffer[4096]; + getpwuid_r(getuid(), &pw, pw_buffer, sizeof(pw_buffer), &p_pw); + if(p_pw && p_pw->pw_dir) + { + homeDir = p_pw->pw_dir; + } + + AWS_LOGSTREAM_INFO(FILE_SYSTEM_UTILS_LOG_TAG, "Pulled " << homeDir << " as home directory from the OS."); + } + + Aws::String retVal = homeDir.size() > 0 ? Aws::Utils::StringUtils::Trim(homeDir.c_str()) : ""; + if(!retVal.empty()) + { + if(retVal.at(retVal.length() - 1) != PATH_DELIM) + { + AWS_LOGSTREAM_DEBUG(FILE_SYSTEM_UTILS_LOG_TAG, "Home directory is missing the final " << PATH_DELIM << " appending one to normalize"); + retVal += PATH_DELIM; + } + } + + AWS_LOGSTREAM_DEBUG(FILE_SYSTEM_UTILS_LOG_TAG, "Final Home Directory is " << retVal); + + return retVal; +} + +bool CreateDirectoryIfNotExists(const char* path, bool createParentDirs) +{ + Aws::String directoryName = path; + AWS_LOGSTREAM_INFO(FILE_SYSTEM_UTILS_LOG_TAG, "Creating directory " << directoryName); + + for (size_t i = (createParentDirs ? 0 : directoryName.size() - 1); i < directoryName.size(); i++) + { + // Create the parent directory if we find a delimiter and the delimiter is not the first char, or if this is the target directory. + if (i != 0 && (directoryName[i] == FileSystem::PATH_DELIM || i == directoryName.size() - 1)) + { + if (directoryName[i] == FileSystem::PATH_DELIM) + { + directoryName[i] = '\0'; + } + int errorCode = mkdir(directoryName.c_str(), S_IRWXU | S_IRWXG | S_IRWXO); + if (errorCode != 0 && errno != EEXIST) + { + AWS_LOGSTREAM_ERROR(FILE_SYSTEM_UTILS_LOG_TAG, "Creation of directory " << directoryName.c_str() << " returned code: " << errno); + return false; + } + AWS_LOGSTREAM_DEBUG(FILE_SYSTEM_UTILS_LOG_TAG, "Creation of directory " << directoryName.c_str() << " returned code: " << errno); + directoryName[i] = FileSystem::PATH_DELIM; + } + } + return true; +} + +bool RemoveFileIfExists(const char* path) +{ + AWS_LOGSTREAM_INFO(FILE_SYSTEM_UTILS_LOG_TAG, "Deleting file: " << path); + + int errorCode = unlink(path); + AWS_LOGSTREAM_DEBUG(FILE_SYSTEM_UTILS_LOG_TAG, "Deletion of file: " << path << " Returned error code: " << errno); + return errorCode == 0 || errno == ENOENT; +} + +bool RemoveDirectoryIfExists(const char* path) +{ + AWS_LOGSTREAM_INFO(FILE_SYSTEM_UTILS_LOG_TAG, "Deleting directory: " << path); + int errorCode = rmdir(path); + AWS_LOGSTREAM_DEBUG(FILE_SYSTEM_UTILS_LOG_TAG, "Deletion of directory: " << path << " Returned error code: " << errno); + return errorCode == 0 || errno == ENOTDIR || errno == ENOENT; +} + +bool RelocateFileOrDirectory(const char* from, const char* to) +{ + AWS_LOGSTREAM_INFO(FILE_SYSTEM_UTILS_LOG_TAG, "Moving file at " << from << " to " << to); + + int errorCode = std::rename(from, to); + + AWS_LOGSTREAM_DEBUG(FILE_SYSTEM_UTILS_LOG_TAG, "The moving operation of file at " << from << " to " << to << " Returned error code of " << errno); + return errorCode == 0; +} + +Aws::String CreateTempFilePath() +{ + Aws::StringStream ss; + auto dt = Aws::Utils::DateTime::Now(); + + ss << dt.ToGmtString("%Y%m%dT%H%M%S") << dt.Millis() << Aws::String(Aws::Utils::UUID::RandomUUID()); + Aws::String tempFile(ss.str()); + + AWS_LOGSTREAM_DEBUG(FILE_SYSTEM_UTILS_LOG_TAG, "CreateTempFilePath generated: " << tempFile); + + return tempFile; +} + +Aws::String GetExecutableDirectory() +{ + char dest[PATH_MAX]; + memset(dest, 0, PATH_MAX); +#ifdef __APPLE__ + uint32_t destSize = PATH_MAX; + if (_NSGetExecutablePath(dest, &destSize) == 0) +#else + size_t destSize = PATH_MAX; + if (readlink("/proc/self/exe", dest, destSize)) +#endif + { + Aws::String executablePath(dest); + auto lastSlash = executablePath.find_last_of('/'); + if(lastSlash != std::string::npos) + { + return executablePath.substr(0, lastSlash); + } + } + return "./"; +} + +Aws::UniquePtr<Directory> OpenDirectory(const Aws::String& path, const Aws::String& relativePath) +{ + return Aws::MakeUnique<PosixDirectory>(FILE_SYSTEM_UTILS_LOG_TAG, path, relativePath); +} + +} // namespace FileSystem +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/platform/linux-shared/OSVersionInfo.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/platform/linux-shared/OSVersionInfo.cpp new file mode 100644 index 0000000000..040173a2e5 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/platform/linux-shared/OSVersionInfo.cpp @@ -0,0 +1,59 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/platform/OSVersionInfo.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> +#include <aws/core/utils/StringUtils.h> +#include <sys/utsname.h> + +namespace Aws +{ +namespace OSVersionInfo +{ + +Aws::String GetSysCommandOutput(const char* command) +{ + Aws::String outputStr; + FILE* outputStream; + const int maxBufferSize = 256; + char outputBuffer[maxBufferSize]; + + outputStream = popen(command, "r"); + + if (outputStream) + { + while (!feof(outputStream)) + { + if (fgets(outputBuffer, maxBufferSize, outputStream) != nullptr) + { + outputStr.append(outputBuffer); + } + } + + pclose(outputStream); + + return Aws::Utils::StringUtils::Trim(outputStr.c_str()); + } + + return {}; +} + + +Aws::String ComputeOSVersionString() +{ + utsname name; + int32_t success = uname(&name); + if(success >= 0) + { + Aws::StringStream ss; + ss << name.sysname << "/" << name.release << " " << name.machine; + return ss.str(); + } + + return "non-windows/unknown"; +} + +} // namespace OSVersionInfo +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/platform/linux-shared/Security.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/platform/linux-shared/Security.cpp new file mode 100644 index 0000000000..286de1a948 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/platform/linux-shared/Security.cpp @@ -0,0 +1,26 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/platform/Security.h> + +#include <string.h> + +namespace Aws +{ +namespace Security +{ + +void SecureMemClear(unsigned char *data, size_t length) +{ +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) + memset_s(data, length, 0, length); +#else + memset(data, 0, length); + asm volatile("" : "+m" (data)); +#endif +} + +} // namespace Security +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/platform/linux-shared/Time.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/platform/linux-shared/Time.cpp new file mode 100644 index 0000000000..7a0d3d1c0a --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/platform/linux-shared/Time.cpp @@ -0,0 +1,31 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/platform/Time.h> + +#include <time.h> + +namespace Aws +{ +namespace Time +{ + +time_t TimeGM(struct tm* const t) +{ + return timegm(t); +} + +void LocalTime(tm* t, std::time_t time) +{ + localtime_r(&time, t); +} + +void GMTime(tm* t, std::time_t time) +{ + gmtime_r(&time, t); +} + +} // namespace Time +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/ARN.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/ARN.cpp new file mode 100644 index 0000000000..dac358c09d --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/ARN.cpp @@ -0,0 +1,46 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/ARN.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/logging/LogMacros.h> + +namespace Aws +{ + namespace Utils + { + ARN::ARN(const Aws::String& arnString) + { + m_valid = false; + + // An ARN can be identified as any string starting with arn: with 6 defined segments each separated by a : + const auto result = StringUtils::Split(arnString, ':', StringUtils::SplitOptions::INCLUDE_EMPTY_ENTRIES); + + if (result.size() < 6) + { + return; + } + + if (result[0] != "arn") + { + return; + } + + m_arnString = arnString; + m_partition = result[1]; + m_service = result[2]; + m_region = result[3]; + m_accountId = result[4]; + m_resource = result[5]; + + for (size_t i = 6; i < result.size(); i++) + { + m_resource += ":" + result[i]; + } + + m_valid = true; + } + } +}
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/Array.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/Array.cpp new file mode 100644 index 0000000000..43e7863421 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/Array.cpp @@ -0,0 +1,65 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/Array.h> + +#include <aws/core/platform/Security.h> + +namespace Aws +{ + namespace Utils + { + Array<CryptoBuffer> CryptoBuffer::Slice(size_t sizeOfSlice) const + { + assert(sizeOfSlice <= GetLength()); + + size_t numberOfSlices = (GetLength() + sizeOfSlice - 1) / sizeOfSlice; + size_t currentSliceIndex = 0; + Array<CryptoBuffer> slices(numberOfSlices); + + for (size_t i = 0; i < numberOfSlices - 1; ++i) + { + CryptoBuffer newArray(sizeOfSlice); + for (size_t cpyIdx = 0; cpyIdx < newArray.GetLength(); ++cpyIdx) + { + newArray[cpyIdx] = GetItem(cpyIdx + currentSliceIndex); + } + currentSliceIndex += sizeOfSlice; + slices[i] = std::move(newArray); + } + + CryptoBuffer lastArray(GetLength() % sizeOfSlice == 0 ? sizeOfSlice : GetLength() % sizeOfSlice ); + for (size_t cpyIdx = 0; cpyIdx < lastArray.GetLength(); ++cpyIdx) + { + lastArray[cpyIdx] = GetItem(cpyIdx + currentSliceIndex); + } + slices[slices.GetLength() - 1] = std::move(lastArray); + + return slices; + } + + CryptoBuffer& CryptoBuffer::operator^(const CryptoBuffer& operand) + { + size_t smallestSize = std::min<size_t>(GetLength(), operand.GetLength()); + for (size_t i = 0; i < smallestSize; ++i) + { + (*this)[i] ^= operand[i]; + } + + return *this; + } + + /** + * Zero out the array securely + */ + void CryptoBuffer::Zero() + { + if (GetUnderlyingData()) + { + Aws::Security::SecureMemClear(GetUnderlyingData(), GetLength()); + } + } + } +}
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/DNS.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/DNS.cpp new file mode 100644 index 0000000000..ce588150e2 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/DNS.cpp @@ -0,0 +1,55 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/DNS.h> +#include <aws/core/utils/StringUtils.h> + +namespace Aws +{ + namespace Utils + { + bool IsValidDnsLabel(const Aws::String& label) + { + // Valid DNS hostnames are composed of valid DNS labels separated by a period. + // Valid DNS labels are characterized by the following: + // 1- Only contains alphanumeric characters and/or dashes + // 2- Cannot start or end with a dash + // 3- Have a maximum length of 63 characters (the entirety of the domain name should be less than 255 bytes) + + if (label.empty()) + return false; + + if (label.size() > 63) + return false; + + if (!StringUtils::IsAlnum(label.front())) + return false; // '-' is not acceptable as the first character + + if (!StringUtils::IsAlnum(label.back())) + return false; // '-' is not acceptable as the last character + + for (size_t i = 1, e = label.size() - 1; i < e; ++i) + { + auto c = label[i]; + if (c != '-' && !StringUtils::IsAlnum(c)) + return false; + } + + return true; + } + + bool IsValidHost(const Aws::String& host) + { + // Valid DNS hostnames are composed of valid DNS labels separated by a period. + auto labels = StringUtils::Split(host, '.'); + if (labels.empty()) + { + return false; + } + + return !std::any_of(labels.begin(), labels.end(), [](const Aws::String& label){ return !IsValidDnsLabel(label); }); + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/DateTimeCommon.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/DateTimeCommon.cpp new file mode 100644 index 0000000000..b690c90c2d --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/DateTimeCommon.cpp @@ -0,0 +1,1502 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/DateTime.h> + +#include <aws/core/platform/Time.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <time.h> +#include <cassert> +#include <iostream> +#include <cstring> + +static const char* CLASS_TAG = "DateTime"; +static const char* RFC822_DATE_FORMAT_STR_MINUS_Z = "%a, %d %b %Y %H:%M:%S"; +static const char* RFC822_DATE_FORMAT_STR_WITH_Z = "%a, %d %b %Y %H:%M:%S %Z"; +static const char* ISO_8601_LONG_DATE_FORMAT_STR = "%Y-%m-%dT%H:%M:%SZ"; +static const char* ISO_8601_LONG_BASIC_DATE_FORMAT_STR = "%Y%m%dT%H%M%SZ"; + +using namespace Aws::Utils; + + +std::tm CreateZeroedTm() +{ + std::tm timeStruct; + timeStruct.tm_hour = 0; + timeStruct.tm_isdst = -1; + timeStruct.tm_mday = 0; + timeStruct.tm_min = 0; + timeStruct.tm_mon = 0; + timeStruct.tm_sec = 0; + timeStruct.tm_wday = 0; + timeStruct.tm_yday = 0; + timeStruct.tm_year = 0; + + return timeStruct; +} + +//Get the 0-6 week day number from a string representing WeekDay. Case insensitive and will stop on abbreviation +static int GetWeekDayNumberFromStr(const char* timeString, size_t startIndex, size_t stopIndex) +{ + if(stopIndex - startIndex < 3) + { + return -1; + } + + size_t index = startIndex; + + char c = timeString[index]; + char next = 0; + + //it's ugly but this should compile down to EXACTLY 3 comparisons and no memory allocations + switch(c) + { + case 'S': + case 's': + next = timeString[++index]; + switch(next) + { + case 'A': + case 'a': + next = timeString[++index]; + switch (next) + { + case 'T': + case 't': + return 6; + default: + return -1; + } + case 'U': + case 'u': + next = timeString[++index]; + switch (next) + { + case 'N': + case 'n': + return 0; + default: + return -1; + } + default: + return -1; + } + case 'T': + case 't': + next = timeString[++index]; + switch (next) + { + case 'H': + case 'h': + next = timeString[++index]; + switch(next) + { + case 'U': + case 'u': + return 4; + default: + return -1; + } + case 'U': + case 'u': + next = timeString[++index]; + switch(next) + { + case 'E': + case 'e': + return 2; + default: + return -1; + } + default: + return -1; + } + case 'M': + case 'm': + next = timeString[++index]; + switch(next) + { + case 'O': + case 'o': + next = timeString[++index]; + switch (next) + { + case 'N': + case 'n': + return 1; + default: + return -1; + } + default: + return -1; + } + case 'W': + case 'w': + next = timeString[++index]; + switch (next) + { + case 'E': + case 'e': + next = timeString[++index]; + switch (next) + { + case 'D': + case 'd': + return 3; + default: + return -1; + } + default: + return -1; + } + case 'F': + case 'f': + next = timeString[++index]; + switch (next) + { + case 'R': + case 'r': + next = timeString[++index]; + switch (next) + { + case 'I': + case 'i': + return 5; + default: + return -1; + } + default: + return -1; + } + default: + return -1; + } +} + +//Get the 0-11 monthy number from a string representing Month. Case insensitive and will stop on abbreviation +static int GetMonthNumberFromStr(const char* timeString, size_t startIndex, size_t stopIndex) +{ + if (stopIndex - startIndex < 3) + { + return -1; + } + + size_t index = startIndex; + + char c = timeString[index]; + char next = 0; + + //it's ugly but this should compile down to EXACTLY 3 comparisons and no memory allocations + switch (c) + { + case 'M': + case 'm': + next = timeString[++index]; + switch (next) + { + case 'A': + case 'a': + next = timeString[++index]; + switch (next) + { + case 'Y': + case 'y': + return 4; + case 'R': + case 'r': + return 2; + default: + return -1; + } + default: + return -1; + } + case 'A': + case 'a': + next = timeString[++index]; + switch (next) + { + case 'P': + case 'p': + next = timeString[++index]; + switch (next) + { + case 'R': + case 'r': + return 3; + default: + return -1; + } + case 'U': + case 'u': + next = timeString[++index]; + switch (next) + { + case 'G': + case 'g': + return 7; + default: + return -1; + } + default: + return -1; + } + case 'J': + case 'j': + next = timeString[++index]; + switch (next) + { + case 'A': + case 'a': + next = timeString[++index]; + switch (next) + { + case 'N': + case 'n': + return 0; + default: + return -1; + } + case 'U': + case 'u': + next = timeString[++index]; + switch (next) + { + case 'N': + case 'n': + return 5; + case 'L': + case 'l': + return 6; + default: + return -1; + } + default: + return -1; + } + case 'F': + case 'f': + next = timeString[++index]; + switch (next) + { + case 'E': + case 'e': + next = timeString[++index]; + switch (next) + { + case 'B': + case 'b': + return 1; + default: + return -1; + } + default: + return -1; + } + case 'S': + case 's': + next = timeString[++index]; + switch (next) + { + case 'E': + case 'e': + next = timeString[++index]; + switch (next) + { + case 'P': + case 'p': + return 8; + default: + return -1; + } + default: + return -1; + } + case 'O': + case 'o': + next = timeString[++index]; + switch (next) + { + case 'C': + case 'c': + next = timeString[++index]; + switch (next) + { + case 'T': + case 't': + return 9; + default: + return -1; + } + default: + return -1; + } + case 'N': + case 'n': + next = timeString[++index]; + switch (next) + { + case 'O': + case 'o': + next = timeString[++index]; + switch (next) + { + case 'V': + case 'v': + return 10; + default: + return -1; + } + default: + return -1; + } + case 'D': + case 'd': + next = timeString[++index]; + switch (next) + { + case 'E': + case 'e': + next = timeString[++index]; + switch (next) + { + case 'C': + case 'c': + return 11; + default: + return -1; + } + default: + return -1; + } + default: + return -1; + } +} +// Ensure local classes with generic names have internal linkage +namespace { + +class DateParser +{ +public: + DateParser(const char* toParse) : m_error(false), m_toParse(toParse), m_utcAssumed(true) + { + m_parsedTimestamp = CreateZeroedTm(); + memset(m_tz, 0, 7); + } + + virtual ~DateParser() = default; + + virtual void Parse() = 0; + bool WasParseSuccessful() const { return !m_error; } + std::tm& GetParsedTimestamp() { return m_parsedTimestamp; } + bool ShouldIAssumeThisIsUTC() const { return m_utcAssumed; } + const char* GetParsedTimezone() const { return m_tz; } + +protected: + bool m_error; + const char* m_toParse; + std::tm m_parsedTimestamp; + bool m_utcAssumed; + // The size should be at least one byte greater than the maximum possible size so that we could use the last char to indicate the end of the string. + char m_tz[7]; +}; + +static const int MAX_LEN = 100; + +//Before you send me hate mail because I'm doing this manually, I encourage you to try using std::get_time on all platforms and getting +//uniform results. Timezone information doesn't parse on Windows and it hardly even works on GCC 4.9.x. This is the only way to make sure +//the standard is parsed correctly. strptime isn't available one Windows. This code gets hit pretty hard during http serialization/deserialization +//as a result I'm going for no dynamic allocations and linear complexity +class RFC822DateParser : public DateParser +{ +public: + RFC822DateParser(const char* toParse) : DateParser(toParse), m_state(0) + { + } + + /** + * Really simple state machine for the format %a, %d %b %Y %H:%M:%S %Z + */ + void Parse() override + { + size_t len = strlen(m_toParse); + + //DOS check + if (len > MAX_LEN) + { + AWS_LOGSTREAM_WARN(CLASS_TAG, "Incoming String to parse too long with length: " << len) + m_error = true; + return; + } + + size_t index = 0; + size_t stateStartIndex = 0; + int finalState = 8; + + while(m_state <= finalState && !m_error && index < len) + { + char c = m_toParse[index]; + + switch (m_state) + { + case 0: + if(c == ',') + { + int weekNumber = GetWeekDayNumberFromStr(m_toParse, stateStartIndex, index + 1); + + if (weekNumber > -1) + { + m_state = 1; + stateStartIndex = index + 1; + m_parsedTimestamp.tm_wday = weekNumber; + } + else + { + m_error = true; + } + } + else if(!isalpha(c)) + { + m_error = true; + } + break; + case 1: + if (isspace(c)) + { + m_state = 2; + stateStartIndex = index + 1; + } + else + { + m_error = true; + } + break; + case 2: + if (isdigit(c)) + { + m_parsedTimestamp.tm_mday = m_parsedTimestamp.tm_mday * 10 + (c - '0'); + } + else if(isspace(c)) + { + m_state = 3; + stateStartIndex = index + 1; + } + else + { + m_error = true; + } + break; + case 3: + if (isspace(c)) + { + int monthNumber = GetMonthNumberFromStr(m_toParse, stateStartIndex, index + 1); + + if (monthNumber > -1) + { + m_state = 4; + stateStartIndex = index + 1; + m_parsedTimestamp.tm_mon = monthNumber; + } + else + { + m_error = true; + } + } + else if (!isalpha(c)) + { + m_error = true; + } + break; + case 4: + if (isspace(c) && index - stateStartIndex == 4) + { + m_state = 5; + stateStartIndex = index + 1; + m_parsedTimestamp.tm_year -= 1900; + } + else if (isspace(c) && index - stateStartIndex == 2) + { + m_state = 5; + stateStartIndex = index + 1; + m_parsedTimestamp.tm_year += 2000 - 1900; + } + else if (isdigit(c)) + { + m_parsedTimestamp.tm_year = m_parsedTimestamp.tm_year * 10 + (c - '0'); + } + else + { + m_error = true; + } + break; + case 5: + if(c == ':' && index - stateStartIndex == 2) + { + m_state = 6; + stateStartIndex = index + 1; + } + else if (isdigit(c)) + { + m_parsedTimestamp.tm_hour = m_parsedTimestamp.tm_hour * 10 + (c - '0'); + } + else + { + m_error = true; + } + break; + case 6: + if (c == ':' && index - stateStartIndex == 2) + { + m_state = 7; + stateStartIndex = index + 1; + } + else if (isdigit(c)) + { + m_parsedTimestamp.tm_min = m_parsedTimestamp.tm_min * 10 + (c - '0'); + } + else + { + m_error = true; + } + break; + case 7: + if (isspace(c) && index - stateStartIndex == 2) + { + m_state = 8; + stateStartIndex = index + 1; + } + else if (isdigit(c)) + { + m_parsedTimestamp.tm_sec = m_parsedTimestamp.tm_sec * 10 + (c - '0'); + } + else + { + m_error = true; + } + break; + case 8: + if ((isalnum(c) || c == '+' || c == '-') && (index - stateStartIndex < 5)) + { + m_tz[index - stateStartIndex] = c; + } + else + { + m_error = true; + } + break; + default: + m_error = true; + break; + } + + index++; + } + + if (m_tz[0] != 0) + { + m_utcAssumed = IsUTCTimeZoneDesignator(m_tz); + } + + m_error = (m_error || m_state != finalState); + } + + int GetState() const { return m_state; } + +private: + //Detects whether or not the passed in timezone string is a UTC zone. + static bool IsUTCTimeZoneDesignator(const char* str) + { + size_t len = strlen(str); + if (len < 3) + { + return false; + } + + int index = 0; + char c = str[index]; + switch (c) + { + case 'U': + case 'u': + c = str[++index]; + switch(c) + { + case 'T': + case 't': + c = str[++index]; + switch(c) + { + case 'C': + case 'c': + return true; + default: + return false; + } + + case 'C': + case 'c': + c = str[++index]; + switch (c) + { + case 'T': + case 't': + return true; + default: + return false; + } + default: + return false; + } + case 'G': + case 'g': + c = str[++index]; + switch (c) + { + case 'M': + case 'm': + c = str[++index]; + switch (c) + { + case 'T': + case 't': + return true; + default: + return false; + } + default: + return false; + } + case '+': + case '-': + c = str[++index]; + switch (c) + { + case '0': + c = str[++index]; + switch (c) + { + case '0': + c = str[++index]; + switch (c) + { + case '0': + return true; + default: + return false; + } + default: + return false; + } + default: + return false; + } + case 'Z': + return true; + default: + return false; + } + + } + + int m_state; +}; + +//Before you send me hate mail because I'm doing this manually, I encourage you to try using std::get_time on all platforms and getting +//uniform results. Timezone information doesn't parse on Windows and it hardly even works on GCC 4.9.x. This is the only way to make sure +//the standard is parsed correctly. strptime isn't available one Windows. This code gets hit pretty hard during http serialization/deserialization +//as a result I'm going for no dynamic allocations and linear complexity +class ISO_8601DateParser : public DateParser +{ +public: + ISO_8601DateParser(const char* stringToParse) : DateParser(stringToParse), m_state(0) + { + } + + //parses "%Y-%m-%dT%H:%M:%SZ or "%Y-%m-%dT%H:%M:%S.000Z" + void Parse() override + { + size_t len = strlen(m_toParse); + + //DOS check + if (len > MAX_LEN) + { + AWS_LOGSTREAM_WARN(CLASS_TAG, "Incoming String to parse too long with length: " << len) + m_error = true; + return; + } + + size_t index = 0; + size_t stateStartIndex = 0; + const int finalState = 7; + + while (m_state <= finalState && !m_error && index < len) + { + char c = m_toParse[index]; + switch (m_state) + { + case 0: + if (c == '-' && index - stateStartIndex == 4) + { + m_state = 1; + stateStartIndex = index + 1; + m_parsedTimestamp.tm_year -= 1900; + } + else if (isdigit(c)) + { + m_parsedTimestamp.tm_year = m_parsedTimestamp.tm_year * 10 + (c - '0'); + } + else + { + m_error = true; + } + break; + case 1: + if (c == '-' && index - stateStartIndex == 2) + { + m_state = 2; + stateStartIndex = index + 1; + m_parsedTimestamp.tm_mon -= 1; + } + else if (isdigit(c)) + { + m_parsedTimestamp.tm_mon = m_parsedTimestamp.tm_mon * 10 + (c - '0'); + } + else + { + m_error = true; + } + + break; + case 2: + if (c == 'T' && index - stateStartIndex == 2) + { + m_state = 3; + stateStartIndex = index + 1; + } + else if (isdigit(c)) + { + m_parsedTimestamp.tm_mday = m_parsedTimestamp.tm_mday * 10 + (c - '0'); + } + else + { + m_error = true; + } + + break; + case 3: + if (c == ':' && index - stateStartIndex == 2) + { + m_state = 4; + stateStartIndex = index + 1; + } + else if (isdigit(c)) + { + m_parsedTimestamp.tm_hour = m_parsedTimestamp.tm_hour * 10 + (c - '0'); + } + else + { + m_error = true; + } + + break; + case 4: + if (c == ':' && index - stateStartIndex == 2) + { + m_state = 5; + stateStartIndex = index + 1; + } + else if (isdigit(c)) + { + m_parsedTimestamp.tm_min = m_parsedTimestamp.tm_min * 10 + (c - '0'); + } + else + { + m_error = true; + } + + break; + case 5: + if ((c == 'Z' || c == '+' || c == '-' ) && (index - stateStartIndex == 2)) + { + m_tz[0] = c; + m_state = 7; + stateStartIndex = index + 1; + } + else if (c == '.' && index - stateStartIndex == 2) + { + m_state = 6; + stateStartIndex = index + 1; + } + else if (isdigit(c)) + { + m_parsedTimestamp.tm_sec = m_parsedTimestamp.tm_sec * 10 + (c - '0'); + } + else + { + m_error = true; + } + + break; + case 6: + if ((c == 'Z' || c == '+' || c == '-' ) && (index - stateStartIndex == 3)) + { + m_tz[0] = c; + m_state = 7; + stateStartIndex = index + 1; + } + else if(!isdigit(c)) + { + m_error = true; + } + break; + case 7: + if ((isdigit(c) || c == ':') && (index - stateStartIndex < 5)) + { + m_tz[1 + index - stateStartIndex] = c; + } + else + { + m_error = true; + } + break; + default: + m_error = true; + break; + } + index++; + } + + if (m_tz[0] != 0) + { + m_utcAssumed = IsUTCTimeZoneDesignator(m_tz); + } + + m_error = (m_error || m_state != finalState); + } + +private: + //Detects whether or not the passed in timezone string is a UTC zone. + static bool IsUTCTimeZoneDesignator(const char* str) + { + size_t len = strlen(str); + + if (len > 0) + { + if (len == 1 && str[0] == 'Z') + { + return true; + } + + if (len == 6 && str[0] == '+' + && str[1] == '0' + && str[2] == '0' + && str[3] == ':' + && str[4] == '0' + && str[5] == '0') + { + return true; + } + + return false; + } + + return false; + } + + int m_state; +}; + +class ISO_8601BasicDateParser : public DateParser +{ +public: + ISO_8601BasicDateParser(const char* stringToParse) : DateParser(stringToParse), m_state(0) + { + } + + //parses "%Y%m%dT%H%M%SZ or "%Y%m%dT%H%M%S000Z" + void Parse() override + { + size_t len = strlen(m_toParse); + + //DOS check + if (len > MAX_LEN) + { + AWS_LOGSTREAM_WARN(CLASS_TAG, "Incoming String to parse too long with length: " << len) + m_error = true; + return; + } + + size_t index = 0; + size_t stateStartIndex = 0; + const int finalState = 7; + + while (m_state <= finalState && !m_error && index < len) + { + char c = m_toParse[index]; + switch (m_state) + { + // On year: %Y + case 0: + if (isdigit(c)) + { + m_parsedTimestamp.tm_year = m_parsedTimestamp.tm_year * 10 + (c - '0'); + if (index - stateStartIndex == 3) + { + m_state = 1; + stateStartIndex = index + 1; + m_parsedTimestamp.tm_year -= 1900; + } + } + else + { + m_error = true; + } + break; + // On month: %m + case 1: + if (isdigit(c)) + { + m_parsedTimestamp.tm_mon = m_parsedTimestamp.tm_mon * 10 + (c - '0'); + if (index - stateStartIndex == 1) + { + m_state = 2; + stateStartIndex = index + 1; + m_parsedTimestamp.tm_mon -= 1; + } + } + else + { + m_error = true; + } + break; + // On month day: %d + case 2: + if (c == 'T' && index - stateStartIndex == 2) + { + m_state = 3; + stateStartIndex = index + 1; + } + else if (isdigit(c)) + { + m_parsedTimestamp.tm_mday = m_parsedTimestamp.tm_mday * 10 + (c - '0'); + } + else + { + m_error = true; + } + break; + // On hour: %H + case 3: + if (isdigit(c)) + { + m_parsedTimestamp.tm_hour = m_parsedTimestamp.tm_hour * 10 + (c - '0'); + if (index - stateStartIndex == 1) + { + m_state = 4; + stateStartIndex = index + 1; + } + } + else + { + m_error = true; + } + break; + // On minute: %M + case 4: + if (isdigit(c)) + { + m_parsedTimestamp.tm_min = m_parsedTimestamp.tm_min * 10 + (c - '0'); + if (index - stateStartIndex == 1) + { + m_state = 5; + stateStartIndex = index + 1; + } + } + else + { + m_error = true; + } + break; + // On second: %S + case 5: + if (isdigit(c)) + { + m_parsedTimestamp.tm_sec = m_parsedTimestamp.tm_sec * 10 + (c - '0'); + if (index - stateStartIndex == 1) + { + m_state = 6; + stateStartIndex = index + 1; + } + } + else + { + m_error = true; + } + break; + // On TZ: Z or 000Z + case 6: + if ((c == 'Z' || c == '+' || c == '-' ) && (index - stateStartIndex == 0 || index - stateStartIndex == 3)) + { + m_tz[0] = c; + m_state = 7; + stateStartIndex = index + 1; + } + else if (!isdigit(c) || index - stateStartIndex > 3) + { + m_error = true; + } + break; + case 7: + if ((isdigit(c) || c == ':') && (index - stateStartIndex < 5)) + { + m_tz[1 + index - stateStartIndex] = c; + } + else + { + m_error = true; + } + break; + default: + m_error = true; + break; + } + index++; + } + + if (m_tz[0] != 0) + { + m_utcAssumed = IsUTCTimeZoneDesignator(m_tz); + } + + m_error = (m_error || m_state != finalState); + } + +private: + //Detects whether or not the passed in timezone string is a UTC zone. + static bool IsUTCTimeZoneDesignator(const char* str) + { + size_t len = strlen(str); + + if (len > 0) + { + if (len == 1 && str[0] == 'Z') + { + return true; + } + + if (len == 5 && str[0] == '+' + && str[1] == '0' + && str[2] == '0' + && str[3] == '0' + && str[4] == '0') + { + return true; + } + + return false; + } + + return false; + } + + int m_state; +}; + +} // namespace + +DateTime::DateTime(const std::chrono::system_clock::time_point& timepointToAssign) : m_time(timepointToAssign), m_valid(true) +{ +} + +DateTime::DateTime(int64_t millisSinceEpoch) : m_valid(true) +{ + std::chrono::duration<int64_t, std::chrono::milliseconds::period> timestamp(millisSinceEpoch); + m_time = std::chrono::system_clock::time_point(timestamp); +} + +DateTime::DateTime(double epoch_millis) : m_valid(true) +{ + std::chrono::duration<double, std::chrono::seconds::period> timestamp(epoch_millis); + m_time = std::chrono::system_clock::time_point(std::chrono::duration_cast<std::chrono::milliseconds>(timestamp)); +} + +DateTime::DateTime(const Aws::String& timestamp, DateFormat format) : m_valid(true) +{ + ConvertTimestampStringToTimePoint(timestamp.c_str(), format); +} + +DateTime::DateTime(const char* timestamp, DateFormat format) : m_valid(true) +{ + ConvertTimestampStringToTimePoint(timestamp, format); +} + +DateTime::DateTime() : m_valid(true) +{ + //init time_point to default by doing nothing. +} + +DateTime& DateTime::operator=(const Aws::String& timestamp) +{ + *this = DateTime(timestamp, DateFormat::AutoDetect); + return *this; +} + +DateTime& DateTime::operator=(double secondsMillis) +{ + *this = DateTime(secondsMillis); + return *this; +} + +DateTime& DateTime::operator=(int64_t millisSinceEpoch) +{ + *this = DateTime(millisSinceEpoch); + return *this; +} + +DateTime& DateTime::operator=(const std::chrono::system_clock::time_point& timepointToAssign) +{ + *this = DateTime(timepointToAssign); + return *this; +} + +bool DateTime::operator == (const DateTime& other) const +{ + return m_time == other.m_time; +} + +bool DateTime::operator < (const DateTime& other) const +{ + return m_time < other.m_time; +} + +bool DateTime::operator > (const DateTime& other) const +{ + return m_time > other.m_time; +} + +bool DateTime::operator != (const DateTime& other) const +{ + return m_time != other.m_time; +} + +bool DateTime::operator <= (const DateTime& other) const +{ + return m_time <= other.m_time; +} + +bool DateTime::operator >= (const DateTime& other) const +{ + return m_time >= other.m_time; +} + +DateTime DateTime::operator +(const std::chrono::milliseconds& a) const +{ + auto timepointCpy = m_time; + timepointCpy += a; + return DateTime(timepointCpy); +} + +DateTime DateTime::operator -(const std::chrono::milliseconds& a) const +{ + auto timepointCpy = m_time; + timepointCpy -= a; + return DateTime(timepointCpy); +} + +Aws::String DateTime::ToLocalTimeString(DateFormat format) const +{ + switch (format) + { + case DateFormat::ISO_8601: + return ToLocalTimeString(ISO_8601_LONG_DATE_FORMAT_STR); + case DateFormat::ISO_8601_BASIC: + return ToLocalTimeString(ISO_8601_LONG_BASIC_DATE_FORMAT_STR); + case DateFormat::RFC822: + return ToLocalTimeString(RFC822_DATE_FORMAT_STR_WITH_Z); + default: + assert(0); + return ""; + } +} + +Aws::String DateTime::ToLocalTimeString(const char* formatStr) const +{ + struct tm localTimeStamp = ConvertTimestampToLocalTimeStruct(); + + char formattedString[100]; + std::strftime(formattedString, sizeof(formattedString), formatStr, &localTimeStamp); + return formattedString; +} + +Aws::String DateTime::ToGmtString(DateFormat format) const +{ + switch (format) + { + case DateFormat::ISO_8601: + return ToGmtString(ISO_8601_LONG_DATE_FORMAT_STR); + case DateFormat::ISO_8601_BASIC: + return ToGmtString(ISO_8601_LONG_BASIC_DATE_FORMAT_STR); + case DateFormat::RFC822: + { + //Windows erroneously drops the local timezone in for %Z + Aws::String rfc822GmtString = ToGmtString(RFC822_DATE_FORMAT_STR_MINUS_Z); + rfc822GmtString += " GMT"; + return rfc822GmtString; + } + default: + assert(0); + return ""; + } +} + +Aws::String DateTime::ToGmtString(const char* formatStr) const +{ + struct tm gmtTimeStamp = ConvertTimestampToGmtStruct(); + + char formattedString[100]; + std::strftime(formattedString, sizeof(formattedString), formatStr, &gmtTimeStamp); + return formattedString; +} + +double DateTime::SecondsWithMSPrecision() const +{ + std::chrono::duration<double, std::chrono::seconds::period> timestamp(m_time.time_since_epoch()); + return timestamp.count(); +} + +int64_t DateTime::Millis() const +{ + auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(m_time.time_since_epoch()); + return timestamp.count(); +} + +std::chrono::system_clock::time_point DateTime::UnderlyingTimestamp() const +{ + return m_time; +} + +int DateTime::GetYear(bool localTime) const +{ + return GetTimeStruct(localTime).tm_year + 1900; +} + +Month DateTime::GetMonth(bool localTime) const +{ + return static_cast<Aws::Utils::Month>(GetTimeStruct(localTime).tm_mon); +} + +int DateTime::GetDay(bool localTime) const +{ + return GetTimeStruct(localTime).tm_mday; +} + +DayOfWeek DateTime::GetDayOfWeek(bool localTime) const +{ + return static_cast<Aws::Utils::DayOfWeek>(GetTimeStruct(localTime).tm_wday); +} + +int DateTime::GetHour(bool localTime) const +{ + return GetTimeStruct(localTime).tm_hour; +} + +int DateTime::GetMinute(bool localTime) const +{ + return GetTimeStruct(localTime).tm_min; +} + +int DateTime::GetSecond(bool localTime) const +{ + return GetTimeStruct(localTime).tm_sec; +} + +bool DateTime::IsDST(bool localTime) const +{ + return GetTimeStruct(localTime).tm_isdst == 0 ? false : true; +} + +DateTime DateTime::Now() +{ + DateTime dateTime; + dateTime.m_time = std::chrono::system_clock::now(); + return dateTime; +} + +int64_t DateTime::CurrentTimeMillis() +{ + return Now().Millis(); +} + +Aws::String DateTime::CalculateLocalTimestampAsString(const char* formatStr) +{ + DateTime now = Now(); + return now.ToLocalTimeString(formatStr); +} + +Aws::String DateTime::CalculateGmtTimestampAsString(const char* formatStr) +{ + DateTime now = Now(); + return now.ToGmtString(formatStr); +} + +Aws::String DateTime::CalculateGmtTimeWithMsPrecision() +{ + auto now = DateTime::Now(); + struct tm gmtTimeStamp = now.ConvertTimestampToGmtStruct(); + + char formattedString[100]; + auto len = std::strftime(formattedString, sizeof(formattedString), "%Y-%m-%d %H:%M:%S", &gmtTimeStamp); + if (len) + { + auto ms = now.Millis(); + ms = ms - ms / 1000 * 1000; // calculate the milliseconds as fraction. + formattedString[len++] = '.'; + int divisor = 100; + while(divisor) + { + auto digit = ms / divisor; + formattedString[len++] = char('0' + digit); + ms = ms - divisor * digit; + divisor /= 10; + } + formattedString[len] = '\0'; + } + return formattedString; +} + +int DateTime::CalculateCurrentHour() +{ + return Now().GetHour(true); +} + +double DateTime::ComputeCurrentTimestampInAmazonFormat() +{ + return Now().SecondsWithMSPrecision(); +} + +std::chrono::milliseconds DateTime::Diff(const DateTime& a, const DateTime& b) +{ + auto diff = a.m_time - b.m_time; + return std::chrono::duration_cast<std::chrono::milliseconds>(diff); +} + +std::chrono::milliseconds DateTime::operator-(const DateTime& other) const +{ + auto diff = this->m_time - other.m_time; + return std::chrono::duration_cast<std::chrono::milliseconds>(diff); +} + +void DateTime::ConvertTimestampStringToTimePoint(const char* timestamp, DateFormat format) +{ + std::tm timeStruct; + bool isUtc = true; + + switch (format) + { + case DateFormat::RFC822: + { + RFC822DateParser parser(timestamp); + parser.Parse(); + m_valid = parser.WasParseSuccessful(); + isUtc = parser.ShouldIAssumeThisIsUTC(); + timeStruct = parser.GetParsedTimestamp(); + break; + } + case DateFormat::ISO_8601: + { + ISO_8601DateParser parser(timestamp); + parser.Parse(); + m_valid = parser.WasParseSuccessful(); + isUtc = parser.ShouldIAssumeThisIsUTC(); + timeStruct = parser.GetParsedTimestamp(); + break; + } + case DateFormat::ISO_8601_BASIC: + { + ISO_8601BasicDateParser parser(timestamp); + parser.Parse(); + m_valid = parser.WasParseSuccessful(); + isUtc = parser.ShouldIAssumeThisIsUTC(); + timeStruct = parser.GetParsedTimestamp(); + break; + } + case DateFormat::AutoDetect: + { + RFC822DateParser rfcParser(timestamp); + rfcParser.Parse(); + if(rfcParser.WasParseSuccessful()) + { + m_valid = true; + isUtc = rfcParser.ShouldIAssumeThisIsUTC(); + timeStruct = rfcParser.GetParsedTimestamp(); + break; + } + ISO_8601DateParser isoParser(timestamp); + isoParser.Parse(); + if (isoParser.WasParseSuccessful()) + { + m_valid = true; + isUtc = isoParser.ShouldIAssumeThisIsUTC(); + timeStruct = isoParser.GetParsedTimestamp(); + break; + } + ISO_8601BasicDateParser isoBasicParser(timestamp); + isoBasicParser.Parse(); + if (isoBasicParser.WasParseSuccessful()) + { + m_valid = true; + isUtc = isoBasicParser.ShouldIAssumeThisIsUTC(); + timeStruct = isoBasicParser.GetParsedTimestamp(); + break; + } + m_valid = false; + break; + } + default: + assert(0); + } + + if (m_valid) + { + std::time_t tt; + if(isUtc) + { + tt = Aws::Time::TimeGM(&timeStruct); + } + else + { + assert(0); + AWS_LOGSTREAM_WARN(CLASS_TAG, "Non-UTC timestamp detected. This is always a bug. Make the world a better place and fix whatever sent you this timestamp: " << timestamp) + tt = std::mktime(&timeStruct); + } + m_time = std::chrono::system_clock::from_time_t(tt); + } +} + +tm DateTime::GetTimeStruct(bool localTime) const +{ + return localTime ? ConvertTimestampToLocalTimeStruct() : ConvertTimestampToGmtStruct(); +} + +tm DateTime::ConvertTimestampToLocalTimeStruct() const +{ + std::time_t time = std::chrono::system_clock::to_time_t(m_time); + struct tm localTimeStamp; + + Aws::Time::LocalTime(&localTimeStamp, time); + + return localTimeStamp; +} + +tm DateTime::ConvertTimestampToGmtStruct() const +{ + std::time_t time = std::chrono::system_clock::to_time_t(m_time); + struct tm gmtTimeStamp; + Aws::Time::GMTime(&gmtTimeStamp, time); + + return gmtTimeStamp; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/Directory.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/Directory.cpp new file mode 100644 index 0000000000..49ca56b280 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/Directory.cpp @@ -0,0 +1,323 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/platform/FileSystem.h> +#include <aws/core/utils/memory/stl/AWSQueue.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/utils/StringUtils.h> +#include <fstream> +#include <cassert> + +namespace Aws +{ + namespace FileSystem + { + Aws::String Join(const Aws::String& leftSegment, const Aws::String& rightSegment) + { + return Join(PATH_DELIM, leftSegment, rightSegment); + } + + Aws::String Join(char delimiter, const Aws::String& leftSegment, const Aws::String& rightSegment) + { + Aws::StringStream ss; + + if (!leftSegment.empty()) + { + if (leftSegment.back() == delimiter) + { + ss << leftSegment.substr(0, leftSegment.length() - 1); + } + else + { + ss << leftSegment; + } + } + + ss << delimiter; + + if (!rightSegment.empty()) + { + if (rightSegment.front() == delimiter) + { + ss << rightSegment.substr(1); + } + else + { + ss << rightSegment; + } + } + + return ss.str(); + } + + bool DeepCopyDirectory(const char* from, const char* to) + { + if (!from || !to) return false; + + DirectoryTree fromDir(from); + + if (!fromDir) return false; + + CreateDirectoryIfNotExists(to); + DirectoryTree toDir(to); + + if (!toDir) return false; + + bool success(true); + + auto visitor = [to,&success](const DirectoryTree*, const DirectoryEntry& entry) + { + auto newPath = Aws::FileSystem::Join(to, entry.relativePath); + + if (entry.fileType == Aws::FileSystem::FileType::File) + { + Aws::OFStream copyOutStream(newPath.c_str()); + Aws::IFStream originalStream(entry.path.c_str()); + + if(!copyOutStream.good() || !originalStream.good()) + { + success = false; + return false; + } + + std::copy(std::istreambuf_iterator<char>(originalStream), + std::istreambuf_iterator<char>(), std::ostreambuf_iterator<char>(copyOutStream)); + } + else if (entry.fileType == Aws::FileSystem::FileType::Directory) + { + success = CreateDirectoryIfNotExists(newPath.c_str()); + return success; + } + + return success; + }; + + fromDir.TraverseDepthFirst(visitor); + return success; + } + + bool DeepDeleteDirectory(const char* toDelete) + { + bool success(true); + + //scope this to a new stack frame, because we won't be able to delete the root directory + //unless the directory handle has closed. + { + DirectoryTree delDir(toDelete); + + if (!delDir) return false; + + auto visitor = [&success](const DirectoryTree*, const DirectoryEntry& entry) + { + if (entry.fileType == FileType::File) + { + success = RemoveFileIfExists(entry.path.c_str()); + } + else + { + success = RemoveDirectoryIfExists(entry.path.c_str()); + } + + return success; + }; + + delDir.TraverseDepthFirst(visitor, true); + } + + if (success) + { + success = RemoveDirectoryIfExists(toDelete); + } + + return success; + } + + Directory::Directory(const Aws::String& path, const Aws::String& relativePath) + { + auto trimmedPath = Utils::StringUtils::Trim(path.c_str()); + auto trimmedRelativePath = Utils::StringUtils::Trim(relativePath.c_str()); + + if (!trimmedPath.empty() && trimmedPath[trimmedPath.length() - 1] == PATH_DELIM) + { + m_directoryEntry.path = trimmedPath.substr(0, trimmedPath.length() - 1); + } + else + { + m_directoryEntry.path = trimmedPath; + } + + if (!trimmedRelativePath.empty() && trimmedRelativePath[trimmedRelativePath.length() - 1] == PATH_DELIM) + { + m_directoryEntry.relativePath = trimmedRelativePath.substr(0, trimmedRelativePath.length() - 1); + } + else + { + m_directoryEntry.relativePath = trimmedRelativePath; + } + } + + Aws::UniquePtr<Directory> Directory::Descend(const DirectoryEntry& directoryEntry) + { + assert(directoryEntry.fileType != FileType::File); + return OpenDirectory(directoryEntry.path, directoryEntry.relativePath); + } + + Aws::Vector<Aws::String> Directory::GetAllFilePathsInDirectory(const Aws::String& path) + { + Aws::FileSystem::DirectoryTree tree(path); + Aws::Vector<Aws::String> filesVector; + auto visitor = [&](const Aws::FileSystem::DirectoryTree*, const Aws::FileSystem::DirectoryEntry& entry) + { + if (entry.fileType == Aws::FileSystem::FileType::File) + { + filesVector.push_back(entry.path); + } + return true; + }; + tree.TraverseBreadthFirst(visitor); + return filesVector; + } + + DirectoryTree::DirectoryTree(const Aws::String& path) + { + m_dir = OpenDirectory(path); + } + + DirectoryTree::operator bool() const + { + return m_dir->operator bool(); + } + + bool DirectoryTree::operator==(DirectoryTree& other) + { + return Diff(other).size() == 0; + } + + bool DirectoryTree::operator==(const Aws::String& path) + { + return *this == DirectoryTree(path); + } + + Aws::Map<Aws::String, DirectoryEntry> DirectoryTree::Diff(DirectoryTree& other) + { + Aws::Map<Aws::String, DirectoryEntry> thisEntries; + auto thisTraversal = [&thisEntries](const DirectoryTree*, const DirectoryEntry& entry) + { + thisEntries[entry.relativePath] = entry; + return true; + }; + + Aws::Map<Aws::String, DirectoryEntry> otherEntries; + auto otherTraversal = [&thisEntries, &otherEntries](const DirectoryTree*, const DirectoryEntry& entry) + { + auto thisEntry = thisEntries.find(entry.relativePath); + if (thisEntry != thisEntries.end()) + { + thisEntries.erase(entry.relativePath); + } + else + { + otherEntries[entry.relativePath] = entry; + } + + return true; + }; + + TraverseDepthFirst(thisTraversal); + other.TraverseDepthFirst(otherTraversal); + + thisEntries.insert(otherEntries.begin(), otherEntries.end()); + return thisEntries; + } + + void DirectoryTree::TraverseDepthFirst(const DirectoryEntryVisitor& visitor, bool postOrderTraversal) + { + TraverseDepthFirst(*m_dir, visitor, postOrderTraversal); + m_dir = OpenDirectory(m_dir->GetPath()); + } + + void DirectoryTree::TraverseBreadthFirst(const DirectoryEntryVisitor& visitor) + { + TraverseBreadthFirst(*m_dir, visitor); + m_dir = OpenDirectory(m_dir->GetPath()); + } + + void DirectoryTree::TraverseBreadthFirst(Directory& dir, const DirectoryEntryVisitor& visitor) + { + if (!dir) + { + return; + } + + Aws::Queue<DirectoryEntry> queue; + while (DirectoryEntry&& entry = dir.Next()) + { + queue.push(std::move(entry)); + } + + while (queue.size() > 0) + { + auto entry = queue.front(); + queue.pop(); + if(visitor(this, entry)) + { + if(entry.fileType == FileType::Directory) + { + auto currentDir = dir.Descend(entry); + + while (DirectoryEntry&& dirEntry = currentDir->Next()) + { + queue.push(std::move(dirEntry)); + } + } + } + else + { + return; + } + } + } + + bool DirectoryTree::TraverseDepthFirst(Directory& dir, const DirectoryEntryVisitor& visitor, bool postOrder) + { + if (!dir) + { + return true; + } + + bool exitTraversal(false); + DirectoryEntry entry; + + while ((entry = dir.Next()) && !exitTraversal) + { + if(!postOrder) + { + if(!visitor(this, entry)) + { + return false; + } + } + + if (entry.fileType == FileType::Directory) + { + auto subDir = dir.Descend(entry); + exitTraversal = !TraverseDepthFirst(*subDir, visitor, postOrder); + } + + if (postOrder) + { + if (!visitor(this, entry)) + { + return false; + } + } + } + + return !exitTraversal; + } + + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/EnumParseOverflowContainer.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/EnumParseOverflowContainer.cpp new file mode 100644 index 0000000000..eaeba1d910 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/EnumParseOverflowContainer.cpp @@ -0,0 +1,33 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/EnumParseOverflowContainer.h> +#include <aws/core/utils/logging/LogMacros.h> + +using namespace Aws::Utils; +using namespace Aws::Utils::Threading; + +static const char LOG_TAG[] = "EnumParseOverflowContainer"; + +const Aws::String& EnumParseOverflowContainer::RetrieveOverflow(int hashCode) const +{ + ReaderLockGuard guard(m_overflowLock); + auto foundIter = m_overflowMap.find(hashCode); + if (foundIter != m_overflowMap.end()) + { + AWS_LOGSTREAM_DEBUG(LOG_TAG, "Found value " << foundIter->second << " for hash " << hashCode << " from enum overflow container."); + return foundIter->second; + } + + AWS_LOGSTREAM_ERROR(LOG_TAG, "Could not find a previously stored overflow value for hash " << hashCode << ". This will likely break some requests."); + return m_emptyString; +} + +void EnumParseOverflowContainer::StoreOverflow(int hashCode, const Aws::String& value) +{ + WriterLockGuard guard(m_overflowLock); + AWS_LOGSTREAM_WARN(LOG_TAG, "Encountered enum member " << value << " which is not modeled in your clients. You should update your clients when you get a chance."); + m_overflowMap[hashCode] = value; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/FileSystemUtils.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/FileSystemUtils.cpp new file mode 100644 index 0000000000..c47f750960 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/FileSystemUtils.cpp @@ -0,0 +1,51 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/FileSystemUtils.h> + +using namespace Aws::Utils; + +Aws::String PathUtils::GetFileNameFromPathWithoutExt(const Aws::String& path) +{ + Aws::String fileName = Aws::Utils::PathUtils::GetFileNameFromPathWithExt(path); + size_t endPos = fileName.find_last_of('.'); + if (endPos == std::string::npos) + { + return fileName; + } + if (endPos == 0) // fileName is "." + { + return {}; + } + + return fileName.substr(0, endPos); +} + +Aws::String PathUtils::GetFileNameFromPathWithExt(const Aws::String& path) +{ + if (path.size() == 0) + { + return path; + } + + size_t startPos = path.find_last_of(Aws::FileSystem::PATH_DELIM); + if (startPos == path.size() - 1) + { + return {}; + } + + if (startPos == std::string::npos) + { + startPos = 0; + } + else + { + startPos += 1; + } + + size_t endPos = path.size() - 1; + + return path.substr(startPos, endPos - startPos + 1); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/GetTheLights.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/GetTheLights.cpp new file mode 100644 index 0000000000..6e78b546ab --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/GetTheLights.cpp @@ -0,0 +1,36 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include <aws/core/utils/GetTheLights.h> +#include <cassert> + +namespace Aws +{ + namespace Utils + { + GetTheLights::GetTheLights() : m_value(0) + { + } + + void GetTheLights::EnterRoom(std::function<void()> &&callable) + { + int cpy = ++m_value; + assert(cpy > 0); + if(cpy == 1) + { + callable(); + } + } + + void GetTheLights::LeaveRoom(std::function<void()> &&callable) + { + int cpy = --m_value; + assert(cpy >= 0); + if(cpy == 0) + { + callable(); + } + } + } +}
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/HashingUtils.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/HashingUtils.cpp new file mode 100644 index 0000000000..147bddf33e --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/HashingUtils.cpp @@ -0,0 +1,236 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/HashingUtils.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/base64/Base64.h> +#include <aws/core/utils/crypto/Sha256.h> +#include <aws/core/utils/crypto/Sha256HMAC.h> +#include <aws/core/utils/crypto/MD5.h> +#include <aws/core/utils/Outcome.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> +#include <aws/core/utils/memory/stl/AWSList.h> + +#include <iomanip> + +using namespace Aws::Utils; +using namespace Aws::Utils::Base64; +using namespace Aws::Utils::Crypto; + +// internal buffers are fixed-size arrays, so this is harmless memory-management wise +static Aws::Utils::Base64::Base64 s_base64; + +// Aws Glacier Tree Hash calculates hash value for each 1MB data +const static size_t TREE_HASH_ONE_MB = 1024 * 1024; + +Aws::String HashingUtils::Base64Encode(const ByteBuffer& message) +{ + return s_base64.Encode(message); +} + +ByteBuffer HashingUtils::Base64Decode(const Aws::String& encodedMessage) +{ + return s_base64.Decode(encodedMessage); +} + +ByteBuffer HashingUtils::CalculateSHA256HMAC(const ByteBuffer& toSign, const ByteBuffer& secret) +{ + Sha256HMAC hash; + return hash.Calculate(toSign, secret).GetResult(); +} + +ByteBuffer HashingUtils::CalculateSHA256(const Aws::String& str) +{ + Sha256 hash; + return hash.Calculate(str).GetResult(); +} + +ByteBuffer HashingUtils::CalculateSHA256(Aws::IOStream& stream) +{ + Sha256 hash; + return hash.Calculate(stream).GetResult(); +} + +/** + * This function is only used by HashingUtils::CalculateSHA256TreeHash() in this cpp file + * It's a helper function be used to compute the TreeHash defined at: + * http://docs.aws.amazon.com/amazonglacier/latest/dev/checksum-calculations.html + */ +static ByteBuffer TreeHashFinalCompute(Aws::List<ByteBuffer>& input) +{ + Sha256 hash; + assert(input.size() != 0); + + // O(n) time complexity of merging (n + n/2 + n/4 + n/8 +...+ 1) + while (input.size() > 1) + { + auto iter = input.begin(); + // if only one element left, just left it there + while (std::next(iter) != input.end()) + { + // if >= two elements + Aws::String str(reinterpret_cast<char*>(iter->GetUnderlyingData()), iter->GetLength()); + // list erase returns iterator of next element next to the erased element or end() if erased the last one + // list insert inserts element before pos, here we erase two elements, and insert a new element + iter = input.erase(iter); + str.append(reinterpret_cast<char*>(iter->GetUnderlyingData()), iter->GetLength()); + iter = input.erase(iter); + input.insert(iter, hash.Calculate(str).GetResult()); + + if (iter == input.end()) break; + } // while process to the last element + } // while the list has only one element left + + return *(input.begin()); +} + +ByteBuffer HashingUtils::CalculateSHA256TreeHash(const Aws::String& str) +{ + Sha256 hash; + if (str.size() == 0) + { + return hash.Calculate(str).GetResult(); + } + + Aws::List<ByteBuffer> input; + size_t pos = 0; + while (pos < str.size()) + { + input.push_back(hash.Calculate(Aws::String(str, pos, TREE_HASH_ONE_MB)).GetResult()); + pos += TREE_HASH_ONE_MB; + } + + return TreeHashFinalCompute(input); +} + +ByteBuffer HashingUtils::CalculateSHA256TreeHash(Aws::IOStream& stream) +{ + Sha256 hash; + Aws::List<ByteBuffer> input; + auto currentPos = stream.tellg(); + if (currentPos == std::ios::pos_type(-1)) + { + currentPos = 0; + stream.clear(); + } + stream.seekg(0, stream.beg); + Array<char> streamBuffer(TREE_HASH_ONE_MB); + while (stream.good()) + { + stream.read(streamBuffer.GetUnderlyingData(), TREE_HASH_ONE_MB); + auto bytesRead = stream.gcount(); + if (bytesRead > 0) + { + input.push_back(hash.Calculate(Aws::String(reinterpret_cast<char*>(streamBuffer.GetUnderlyingData()), static_cast<size_t>(bytesRead))).GetResult()); + } + } + stream.clear(); + stream.seekg(currentPos, stream.beg); + + if (input.size() == 0) + { + return hash.Calculate("").GetResult(); + } + return TreeHashFinalCompute(input); +} + +Aws::String HashingUtils::HexEncode(const ByteBuffer& message) +{ + Aws::String encoded; + encoded.reserve(2 * message.GetLength()); + + for (unsigned i = 0; i < message.GetLength(); ++i) + { + encoded.push_back("0123456789abcdef"[message[i] >> 4]); + encoded.push_back("0123456789abcdef"[message[i] & 0x0f]); + } + + return encoded; +} + +ByteBuffer HashingUtils::HexDecode(const Aws::String& str) +{ + //number of characters should be even + assert(str.length() % 2 == 0); + assert(str.length() >= 2); + + if(str.length() < 2 || str.length() % 2 != 0) + { + return ByteBuffer(); + } + + size_t strLength = str.length(); + size_t readIndex = 0; + + if(str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) + { + strLength -= 2; + readIndex = 2; + } + + ByteBuffer hexBuffer(strLength / 2); + size_t bufferIndex = 0; + + for (size_t i = readIndex; i < str.length(); i += 2) + { + if(!StringUtils::IsAlnum(str[i]) || !StringUtils::IsAlnum(str[i + 1])) + { + //contains non-hex characters + assert(0); + } + + char firstChar = str[i]; + uint8_t distance = firstChar - '0'; + + if(isalpha(firstChar)) + { + firstChar = static_cast<char>(toupper(firstChar)); + distance = firstChar - 'A' + 10; + } + + unsigned char val = distance * 16; + + char secondChar = str[i + 1]; + distance = secondChar - '0'; + + if(isalpha(secondChar)) + { + secondChar = static_cast<char>(toupper(secondChar)); + distance = secondChar - 'A' + 10; + } + + val += distance; + hexBuffer[bufferIndex++] = val; + } + + return hexBuffer; +} + +ByteBuffer HashingUtils::CalculateMD5(const Aws::String& str) +{ + MD5 hash; + return hash.Calculate(str).GetResult(); +} + +ByteBuffer HashingUtils::CalculateMD5(Aws::IOStream& stream) +{ + MD5 hash; + return hash.Calculate(stream).GetResult(); +} + +int HashingUtils::HashString(const char* strToHash) +{ + if (!strToHash) + return 0; + + unsigned hash = 0; + while (char charValue = *strToHash++) + { + hash = charValue + 31 * hash; + } + + return hash; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/StringUtils.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/StringUtils.cpp new file mode 100644 index 0000000000..e1deb3f046 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/StringUtils.cpp @@ -0,0 +1,421 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> +#include <algorithm> +#include <iomanip> +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include <functional> + +#ifdef _WIN32 +#include <Windows.h> +#endif + +using namespace Aws::Utils; + +void StringUtils::Replace(Aws::String& s, const char* search, const char* replace) +{ + if(!search || !replace) + { + return; + } + + size_t replaceLength = strlen(replace); + size_t searchLength = strlen(search); + + for (std::size_t pos = 0;; pos += replaceLength) + { + pos = s.find(search, pos); + if (pos == Aws::String::npos) + break; + + s.erase(pos, searchLength); + s.insert(pos, replace); + } +} + + +Aws::String StringUtils::ToLower(const char* source) +{ + Aws::String copy; + size_t sourceLength = strlen(source); + copy.resize(sourceLength); + //appease the latest whims of the VC++ 2017 gods + std::transform(source, source + sourceLength, copy.begin(), [](unsigned char c) { return (char)::tolower(c); }); + + return copy; +} + + +Aws::String StringUtils::ToUpper(const char* source) +{ + Aws::String copy; + size_t sourceLength = strlen(source); + copy.resize(sourceLength); + //appease the latest whims of the VC++ 2017 gods + std::transform(source, source + sourceLength, copy.begin(), [](unsigned char c) { return (char)::toupper(c); }); + + return copy; +} + + +bool StringUtils::CaselessCompare(const char* value1, const char* value2) +{ + Aws::String value1Lower = ToLower(value1); + Aws::String value2Lower = ToLower(value2); + + return value1Lower == value2Lower; +} + +Aws::Vector<Aws::String> StringUtils::Split(const Aws::String& toSplit, char splitOn) +{ + return Split(toSplit, splitOn, SIZE_MAX, SplitOptions::NOT_SET); +} + +Aws::Vector<Aws::String> StringUtils::Split(const Aws::String& toSplit, char splitOn, SplitOptions option) +{ + return Split(toSplit, splitOn, SIZE_MAX, option); +} + +Aws::Vector<Aws::String> StringUtils::Split(const Aws::String& toSplit, char splitOn, size_t numOfTargetParts) +{ + return Split(toSplit, splitOn, numOfTargetParts, SplitOptions::NOT_SET); +} + +Aws::Vector<Aws::String> StringUtils::Split(const Aws::String& toSplit, char splitOn, size_t numOfTargetParts, SplitOptions option) +{ + Aws::Vector<Aws::String> returnValues; + Aws::StringStream input(toSplit); + Aws::String item; + + while(returnValues.size() < numOfTargetParts - 1 && std::getline(input, item, splitOn)) + { + if (!item.empty() || option == SplitOptions::INCLUDE_EMPTY_ENTRIES) + { + returnValues.emplace_back(std::move(item)); + } + } + + if (std::getline(input, item, static_cast<char>(EOF))) + { + if (option != SplitOptions::INCLUDE_EMPTY_ENTRIES) + { + // Trim all leading delimiters. + item.erase(item.begin(), std::find_if(item.begin(), item.end(), [splitOn](int ch) { return ch != splitOn; })); + if (!item.empty()) + { + returnValues.emplace_back(std::move(item)); + } + } + else + { + returnValues.emplace_back(std::move(item)); + } + + } + // To handle the case when there are trailing delimiters. + else if (!toSplit.empty() && toSplit.back() == splitOn && option == SplitOptions::INCLUDE_EMPTY_ENTRIES) + { + returnValues.emplace_back(); + } + + return returnValues; +} + +Aws::Vector<Aws::String> StringUtils::SplitOnLine(const Aws::String& toSplit) +{ + Aws::StringStream input(toSplit); + Aws::Vector<Aws::String> returnValues; + Aws::String item; + + while (std::getline(input, item)) + { + if (item.size() > 0) + { + returnValues.push_back(item); + } + } + + return returnValues; +} + + +Aws::String StringUtils::URLEncode(const char* unsafe) +{ + Aws::StringStream escaped; + escaped.fill('0'); + escaped << std::hex << std::uppercase; + + size_t unsafeLength = strlen(unsafe); + for (auto i = unsafe, n = unsafe + unsafeLength; i != n; ++i) + { + char c = *i; + if (IsAlnum(c) || c == '-' || c == '_' || c == '.' || c == '~') + { + escaped << (char)c; + } + else + { + //this unsigned char cast allows us to handle unicode characters. + escaped << '%' << std::setw(2) << int((unsigned char)c) << std::setw(0); + } + } + + return escaped.str(); +} + +Aws::String StringUtils::UTF8Escape(const char* unicodeString, const char* delimiter) +{ + Aws::StringStream escaped; + escaped.fill('0'); + escaped << std::hex << std::uppercase; + + size_t unsafeLength = strlen(unicodeString); + for (auto i = unicodeString, n = unicodeString + unsafeLength; i != n; ++i) + { + int c = *i; + if (c >= ' ' && c < 127 ) + { + escaped << (char)c; + } + else + { + //this unsigned char cast allows us to handle unicode characters. + escaped << delimiter << std::setw(2) << int((unsigned char)c) << std::setw(0); + } + } + + return escaped.str(); +} + +Aws::String StringUtils::URLEncode(double unsafe) +{ + char buffer[32]; +#if defined(_MSC_VER) && _MSC_VER < 1900 + _snprintf_s(buffer, sizeof(buffer), _TRUNCATE, "%g", unsafe); +#else + snprintf(buffer, sizeof(buffer), "%g", unsafe); +#endif + + return StringUtils::URLEncode(buffer); +} + + +Aws::String StringUtils::URLDecode(const char* safe) +{ + Aws::String unescaped; + + for (; *safe; safe++) + { + switch(*safe) + { + case '%': + { + int hex = 0; + auto ch = *++safe; + if (ch >= '0' && ch <= '9') + { + hex = (ch - '0') * 16; + } + else if (ch >= 'A' && ch <= 'F') + { + hex = (ch - 'A' + 10) * 16; + } + else if (ch >= 'a' && ch <= 'f') + { + hex = (ch - 'a' + 10) * 16; + } + else + { + unescaped.push_back('%'); + if (ch == 0) + { + return unescaped; + } + unescaped.push_back(ch); + break; + } + + ch = *++safe; + if (ch >= '0' && ch <= '9') + { + hex += (ch - '0'); + } + else if (ch >= 'A' && ch <= 'F') + { + hex += (ch - 'A' + 10); + } + else if (ch >= 'a' && ch <= 'f') + { + hex += (ch - 'a' + 10); + } + else + { + unescaped.push_back('%'); + unescaped.push_back(*(safe - 1)); + if (ch == 0) + { + return unescaped; + } + unescaped.push_back(ch); + break; + } + + unescaped.push_back(char(hex)); + break; + } + case '+': + unescaped.push_back(' '); + break; + default: + unescaped.push_back(*safe); + break; + } + } + + return unescaped; +} + +static bool IsSpace(int ch) +{ + if (ch < -1 || ch > 255) + { + return false; + } + + return ::isspace(ch) != 0; +} + +Aws::String StringUtils::LTrim(const char* source) +{ + Aws::String copy(source); + copy.erase(copy.begin(), std::find_if(copy.begin(), copy.end(), [](int ch) { return !IsSpace(ch); })); + return copy; +} + +// trim from end +Aws::String StringUtils::RTrim(const char* source) +{ + Aws::String copy(source); + copy.erase(std::find_if(copy.rbegin(), copy.rend(), [](int ch) { return !IsSpace(ch); }).base(), copy.end()); + return copy; +} + +// trim from both ends +Aws::String StringUtils::Trim(const char* source) +{ + return LTrim(RTrim(source).c_str()); +} + +long long StringUtils::ConvertToInt64(const char* source) +{ + if(!source) + { + return 0; + } + +#ifdef __ANDROID__ + return atoll(source); +#else + return std::atoll(source); +#endif // __ANDROID__ +} + + +long StringUtils::ConvertToInt32(const char* source) +{ + if (!source) + { + return 0; + } + + return std::atol(source); +} + + +bool StringUtils::ConvertToBool(const char* source) +{ + if(!source) + { + return false; + } + + Aws::String strValue = ToLower(source); + if(strValue == "true" || strValue == "1") + { + return true; + } + + return false; +} + + +double StringUtils::ConvertToDouble(const char* source) +{ + if(!source) + { + return 0.0; + } + + return std::strtod(source, NULL); +} + +#ifdef _WIN32 + +Aws::WString StringUtils::ToWString(const char* source) +{ + const auto len = static_cast<int>(std::strlen(source)); + Aws::WString outString; + outString.resize(len); // there is no way UTF-16 would require _more_ code-points than UTF-8 for the _same_ string + const auto result = MultiByteToWideChar(CP_UTF8 /*CodePage*/, + 0 /*dwFlags*/, + source /*lpMultiByteStr*/, + len /*cbMultiByte*/, + &outString[0] /*lpWideCharStr*/, + static_cast<int>(outString.length())/*cchWideChar*/); + if (!result) + { + return L""; + } + outString.resize(result); + return outString; +} + +Aws::String StringUtils::FromWString(const wchar_t* source) +{ + const auto len = static_cast<int>(std::wcslen(source)); + Aws::String output; + if (int requiredSizeInBytes = WideCharToMultiByte(CP_UTF8 /*CodePage*/, + 0 /*dwFlags*/, + source /*lpWideCharStr*/, + len /*cchWideChar*/, + nullptr /*lpMultiByteStr*/, + 0 /*cbMultiByte*/, + nullptr /*lpDefaultChar*/, + nullptr /*lpUsedDefaultChar*/)) + { + output.resize(requiredSizeInBytes); + } + const auto result = WideCharToMultiByte(CP_UTF8 /*CodePage*/, + 0 /*dwFlags*/, + source /*lpWideCharStr*/, + len /*cchWideChar*/, + &output[0] /*lpMultiByteStr*/, + static_cast<int>(output.length()) /*cbMultiByte*/, + nullptr /*lpDefaultChar*/, + nullptr /*lpUsedDefaultChar*/); + if (!result) + { + return ""; + } + output.resize(result); + return output; +} + +#endif diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/TempFile.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/TempFile.cpp new file mode 100644 index 0000000000..7bc07266c9 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/TempFile.cpp @@ -0,0 +1,54 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/FileSystemUtils.h> + +#include <aws/core/platform/FileSystem.h> + +namespace Aws +{ + namespace Utils + { + static Aws::String ComputeTempFileName(const char* prefix, const char* suffix) + { + Aws::String prefixStr; + + if (prefix) + { + prefixStr = prefix; + } + + Aws::String suffixStr; + + if (suffix) + { + suffixStr = suffix; + } + + return prefixStr + Aws::FileSystem::CreateTempFilePath() + suffixStr; + } + + TempFile::TempFile(const char* prefix, const char* suffix, std::ios_base::openmode openFlags) : + FStreamWithFileName(ComputeTempFileName(prefix, suffix).c_str(), openFlags) + { + } + + TempFile::TempFile(const char* prefix, std::ios_base::openmode openFlags) : + FStreamWithFileName(ComputeTempFileName(prefix, nullptr).c_str(), openFlags) + { + } + + TempFile::TempFile(std::ios_base::openmode openFlags) : + FStreamWithFileName(ComputeTempFileName(nullptr, nullptr).c_str(), openFlags) + { + } + + + TempFile::~TempFile() + { + Aws::FileSystem::RemoveFileIfExists(m_fileName.c_str()); + } + } +}
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/UUID.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/UUID.cpp new file mode 100644 index 0000000000..862f3eacdd --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/UUID.cpp @@ -0,0 +1,90 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/UUID.h> +#include <aws/core/utils/HashingUtils.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/crypto/Factories.h> +#include <aws/core/utils/crypto/SecureRandom.h> +#include <iomanip> + +namespace Aws +{ + namespace Utils + { + static const size_t UUID_STR_SIZE = 0x24u; // 36 characters + static const size_t VERSION_LOCATION = 0x06u; + static const size_t VARIANT_LOCATION = 0x08u; + static const unsigned char VERSION = 0x40u; + static const unsigned char VERSION_MASK = 0x0Fu; + static const unsigned char VARIANT = 0x80u; + static const unsigned char VARIANT_MASK = 0x3Fu; + + static void hexify(Aws::String& ss, const unsigned char* toWrite, size_t min, size_t max) + { + for (size_t i = min; i < max; ++i) + { + ss.push_back("0123456789ABCDEF"[toWrite[i] >> 4]); + ss.push_back("0123456789ABCDEF"[toWrite[i] & 0x0F]); + } + } + + UUID::UUID(const Aws::String& uuidToConvert) + { + //GUID has 2 characters per byte + 4 dashes = 36 bytes + assert(uuidToConvert.length() == UUID_STR_SIZE); + memset(m_uuid, 0, sizeof(m_uuid)); + Aws::String escapedHexStr(uuidToConvert); + StringUtils::Replace(escapedHexStr, "-", ""); + assert(escapedHexStr.length() == UUID_BINARY_SIZE * 2); + ByteBuffer&& rawUuid = HashingUtils::HexDecode(escapedHexStr); + memcpy(m_uuid, rawUuid.GetUnderlyingData(), rawUuid.GetLength()); + } + + UUID::UUID(const unsigned char toCopy[UUID_BINARY_SIZE]) + { + memcpy(m_uuid, toCopy, sizeof(m_uuid)); + } + + UUID::operator Aws::String() const + { + Aws::String ss; + ss.reserve(UUID_STR_SIZE); + hexify(ss, m_uuid, 0, 4); + ss.push_back('-'); + + hexify(ss, m_uuid, 4, 6); + ss.push_back('-'); + + hexify(ss, m_uuid, 6, 8); + ss.push_back('-'); + + hexify(ss, m_uuid, 8, 10); + ss.push_back('-'); + + hexify(ss, m_uuid, 10, 16); + + return ss; + } + + UUID UUID::RandomUUID() + { + auto secureRandom = Crypto::CreateSecureRandomBytesImplementation(); + assert(secureRandom); + + unsigned char randomBytes[UUID_BINARY_SIZE]; + memset(randomBytes, 0, UUID_BINARY_SIZE); + secureRandom->GetBytes(randomBytes, UUID_BINARY_SIZE); + //Set version bits to 0100 + //https://tools.ietf.org/html/rfc4122#section-4.1.3 + randomBytes[VERSION_LOCATION] = (randomBytes[VERSION_LOCATION] & VERSION_MASK) | VERSION; + //set variant bits to 10 + //https://tools.ietf.org/html/rfc4122#section-4.1.1 + randomBytes[VARIANT_LOCATION] = (randomBytes[VARIANT_LOCATION] & VARIANT_MASK) | VARIANT; + + return UUID(randomBytes); + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/base64/Base64.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/base64/Base64.cpp new file mode 100644 index 0000000000..2103d6d5a6 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/base64/Base64.cpp @@ -0,0 +1,148 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/base64/Base64.h> +#include <cstring> + +using namespace Aws::Utils::Base64; + +static const uint8_t SENTINEL_VALUE = 255; +static const char BASE64_ENCODING_TABLE_MIME[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +namespace Aws +{ +namespace Utils +{ +namespace Base64 +{ + +Base64::Base64(const char *encodingTable) +{ + if(encodingTable == nullptr) + { + encodingTable = BASE64_ENCODING_TABLE_MIME; + } + + size_t encodingTableLength = strlen(encodingTable); + if(encodingTableLength != 64) + { + encodingTable = BASE64_ENCODING_TABLE_MIME; + encodingTableLength = 64; + } + + memcpy(m_mimeBase64EncodingTable, encodingTable, encodingTableLength); + + memset((void *)m_mimeBase64DecodingTable, 0, 256); + + for(uint32_t i = 0; i < encodingTableLength; ++i) + { + uint32_t index = static_cast<uint32_t>(m_mimeBase64EncodingTable[i]); + m_mimeBase64DecodingTable[index] = static_cast<uint8_t>(i); + } + + m_mimeBase64DecodingTable[(uint32_t)'='] = SENTINEL_VALUE; +} + +Aws::String Base64::Encode(const Aws::Utils::ByteBuffer& buffer) const +{ + size_t bufferLength = buffer.GetLength(); + size_t blockCount = (bufferLength + 2) / 3; + size_t remainderCount = (bufferLength % 3); + + Aws::String outputString; + outputString.reserve(CalculateBase64EncodedLength(buffer)); + + for(size_t i = 0; i < bufferLength; i += 3 ) + { + uint32_t block = buffer[ i ]; + + block <<= 8; + if (i + 1 < bufferLength) + { + block = block | buffer[ i + 1 ]; + } + + block <<= 8; + if (i + 2 < bufferLength) + { + block = block | buffer[ i + 2 ]; + } + + outputString.push_back(m_mimeBase64EncodingTable[(block >> 18) & 0x3F]); + outputString.push_back(m_mimeBase64EncodingTable[(block >> 12) & 0x3F]); + outputString.push_back(m_mimeBase64EncodingTable[(block >> 6) & 0x3F]); + outputString.push_back(m_mimeBase64EncodingTable[block & 0x3F]); + } + + if(remainderCount > 0) + { + outputString[blockCount * 4 - 1] = '='; + if(remainderCount == 1) + { + outputString[blockCount * 4 - 2] = '='; + } + } + + return outputString; +} + +Aws::Utils::ByteBuffer Base64::Decode(const Aws::String& str) const +{ + size_t decodedLength = CalculateBase64DecodedLength(str); + + Aws::Utils::ByteBuffer buffer(decodedLength); + + const char* rawString = str.c_str(); + size_t blockCount = str.length() / 4; + for(size_t i = 0; i < blockCount; ++i) + { + size_t stringIndex = i * 4; + + uint32_t value1 = m_mimeBase64DecodingTable[uint32_t(rawString[stringIndex])]; + uint32_t value2 = m_mimeBase64DecodingTable[uint32_t(rawString[++stringIndex])]; + uint32_t value3 = m_mimeBase64DecodingTable[uint32_t(rawString[++stringIndex])]; + uint32_t value4 = m_mimeBase64DecodingTable[uint32_t(rawString[++stringIndex])]; + + size_t bufferIndex = i * 3; + buffer[bufferIndex] = static_cast<uint8_t>((value1 << 2) | ((value2 >> 4) & 0x03)); + if(value3 != SENTINEL_VALUE) + { + buffer[++bufferIndex] = static_cast<uint8_t>(((value2 << 4) & 0xF0) | ((value3 >> 2) & 0x0F)); + if(value4 != SENTINEL_VALUE) + { + buffer[++bufferIndex] = static_cast<uint8_t>((value3 & 0x03) << 6 | value4); + } + } + } + + return buffer; +} + +size_t Base64::CalculateBase64DecodedLength(const Aws::String& b64input) +{ + const size_t len = b64input.length(); + if(len < 2) + { + return 0; + } + + size_t padding = 0; + + if (b64input[len - 1] == '=' && b64input[len - 2] == '=') //last two chars are = + padding = 2; + else if (b64input[len - 1] == '=') //last char is = + padding = 1; + + return (len * 3 / 4 - padding); +} + +size_t Base64::CalculateBase64EncodedLength(const Aws::Utils::ByteBuffer& buffer) +{ + return 4 * ((buffer.GetLength() + 2) / 3); +} + +} // namespace Base64 +} // namespace Utils +} // namespace Aws
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Cipher.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Cipher.cpp new file mode 100644 index 0000000000..1c844273f4 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Cipher.cpp @@ -0,0 +1,123 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/crypto/Cipher.h> +#include <aws/core/utils/crypto/Factories.h> +#include <aws/core/utils/crypto/SecureRandom.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <cstdlib> +#include <climits> + +//if you are reading this, you are witnessing pure brilliance. +#define IS_BIG_ENDIAN (*(uint16_t*)"\0\xff" < 0x100) + +using namespace Aws::Utils::Crypto; +using namespace Aws::Utils; + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + static const char* LOG_TAG = "Cipher"; + + //swap byte ordering + template<class T> + typename std::enable_if<std::is_unsigned<T>::value, T>::type + bswap(T i, T j = 0u, std::size_t n = 0u) + { + return n == sizeof(T) ? j : + bswap<T>(i >> CHAR_BIT, (j << CHAR_BIT) | (i & (T)(unsigned char)(-1)), n + 1); + } + + CryptoBuffer IncrementCTRCounter(const CryptoBuffer& counter, uint32_t numberOfBlocks) + { + // minium counter size is 12 bytes. This isn't a variable because some compilers + // are stupid and thing that variable is unused. + assert(counter.GetLength() >= 12); + + CryptoBuffer incrementedCounter(counter); + + //get the last 4 bytes and manipulate them as an integer. + uint32_t* ctrPtr = (uint32_t*)(incrementedCounter.GetUnderlyingData() + incrementedCounter.GetLength() - sizeof(int32_t)); + if(IS_BIG_ENDIAN) + { + //you likely are not Big Endian, but + //if it's big endian, just go ahead and increment it... done + *ctrPtr += numberOfBlocks; + } + else + { + //otherwise, swap the byte ordering of the integer we loaded from the buffer (because it is backwards). However, the number of blocks is already properly + //aligned. Once we compute the new value, swap it back so that the mirroring operation goes back to the actual buffer. + *ctrPtr = bswap<uint32_t>(bswap<uint32_t>(*ctrPtr) + numberOfBlocks); + } + + return incrementedCounter; + } + + CryptoBuffer GenerateXRandomBytes(size_t lengthBytes, bool ctrMode) + { + std::shared_ptr<SecureRandomBytes> rng = CreateSecureRandomBytesImplementation(); + + CryptoBuffer bytes(lengthBytes); + size_t lengthToGenerate = ctrMode ? (3 * bytes.GetLength()) / 4 : bytes.GetLength(); + + rng->GetBytes(bytes.GetUnderlyingData(), lengthToGenerate); + + if(!*rng) + { + AWS_LOGSTREAM_FATAL(LOG_TAG, "Random Number generation failed. Abort all crypto operations."); + assert(false); + abort(); + } + + return bytes; + } + + /** + * Generate random number per 4 bytes and use each byte for the byte in the iv + */ + CryptoBuffer SymmetricCipher::GenerateIV(size_t ivLengthBytes, bool ctrMode) + { + CryptoBuffer iv(GenerateXRandomBytes(ivLengthBytes, ctrMode)); + + if(iv.GetLength() == 0) + { + AWS_LOGSTREAM_ERROR(LOG_TAG, "Unable to generate iv of length " << ivLengthBytes); + return iv; + } + + if(ctrMode) + { + //init the counter + size_t length = iv.GetLength(); + //[ nonce 1/4] [ iv 1/2 ] [ ctr 1/4 ] + size_t ctrStart = (length / 2) + (length / 4); + for(; ctrStart < iv.GetLength() - 1; ++ ctrStart) + { + iv[ctrStart] = 0; + } + iv[length - 1] = 1; + } + + return iv; + } + + CryptoBuffer SymmetricCipher::GenerateKey(size_t keyLengthBytes) + { + CryptoBuffer const& key = GenerateXRandomBytes(keyLengthBytes, false); + + if(key.GetLength() == 0) + { + AWS_LOGSTREAM_ERROR(LOG_TAG, "Unable to generate key of length " << keyLengthBytes); + } + + return key; + } + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/ContentCryptoMaterial.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/ContentCryptoMaterial.cpp new file mode 100644 index 0000000000..3036bd70eb --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/ContentCryptoMaterial.cpp @@ -0,0 +1,34 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include <aws/core/utils/crypto/ContentCryptoMaterial.h> +#include <aws/core/utils/crypto/Cipher.h> + +using namespace Aws::Utils::Crypto; + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + ContentCryptoMaterial::ContentCryptoMaterial() : + m_cryptoTagLength(0), m_keyWrapAlgorithm(KeyWrapAlgorithm::NONE), m_contentCryptoScheme(ContentCryptoScheme::NONE) + { + } + + ContentCryptoMaterial::ContentCryptoMaterial(ContentCryptoScheme contentCryptoScheme) : + m_contentEncryptionKey(SymmetricCipher::GenerateKey()), m_cryptoTagLength(0), m_keyWrapAlgorithm(KeyWrapAlgorithm::NONE), m_contentCryptoScheme(contentCryptoScheme) + { + + } + + ContentCryptoMaterial::ContentCryptoMaterial(const Aws::Utils::CryptoBuffer & cek, ContentCryptoScheme contentCryptoScheme) : + m_contentEncryptionKey(cek), m_cryptoTagLength(0), m_keyWrapAlgorithm(KeyWrapAlgorithm::NONE), m_contentCryptoScheme(contentCryptoScheme) + { + + } + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/ContentCryptoScheme.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/ContentCryptoScheme.cpp new file mode 100644 index 0000000000..f39a75df2c --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/ContentCryptoScheme.cpp @@ -0,0 +1,61 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include <aws/core/utils/crypto/ContentCryptoScheme.h> +#include <aws/core/utils/HashingUtils.h> +#include <aws/core/utils/EnumParseOverflowContainer.h> +#include <aws/core/Globals.h> + +using namespace Aws::Utils; + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + namespace ContentCryptoSchemeMapper + { + static const int cryptoScheme_CBC_HASH = HashingUtils::HashString("AES/CBC/PKCS5Padding"); + static const int cryptoScheme_CTR_HASH = HashingUtils::HashString("AES/CTR/NoPadding"); + static const int cryptoScheme_GCM_HASH = HashingUtils::HashString("AES/GCM/NoPadding"); + + ContentCryptoScheme GetContentCryptoSchemeForName(const Aws::String& name) + { + int hashcode = HashingUtils::HashString(name.c_str()); + if (hashcode == cryptoScheme_CBC_HASH) + { + return ContentCryptoScheme::CBC; + } + else if (hashcode == cryptoScheme_CTR_HASH) + { + return ContentCryptoScheme::CTR; + } + else if (hashcode == cryptoScheme_GCM_HASH) + { + return ContentCryptoScheme::GCM; + } + assert(0); + return ContentCryptoScheme::NONE; + } + + Aws::String GetNameForContentCryptoScheme(ContentCryptoScheme enumValue) + { + switch (enumValue) + { + case ContentCryptoScheme::CBC: + return "AES/CBC/PKCS5Padding"; + case ContentCryptoScheme::CTR: + return "AES/CTR/NoPadding"; + case ContentCryptoScheme::GCM: + return "AES/GCM/NoPadding"; + default: + assert(0); + return ""; + } + } + }//namespace ContentCryptoSchemeMapper + } //namespace Crypto + }//namespace Utils +}//namespace Aws
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/CryptoBuf.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/CryptoBuf.cpp new file mode 100644 index 0000000000..2b47097679 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/CryptoBuf.cpp @@ -0,0 +1,348 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/crypto/CryptoBuf.h> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + SymmetricCryptoBufSrc::SymmetricCryptoBufSrc(Aws::IStream& stream, SymmetricCipher& cipher, CipherMode cipherMode, size_t bufferSize) + : + m_isBuf(PUT_BACK_SIZE), m_cipher(cipher), m_stream(stream), m_cipherMode(cipherMode), m_isFinalized(false), + m_bufferSize(bufferSize), m_putBack(PUT_BACK_SIZE) + { + char* end = reinterpret_cast<char*>(m_isBuf.GetUnderlyingData() + m_isBuf.GetLength()); + setg(end, end, end); + } + + SymmetricCryptoBufSrc::pos_type SymmetricCryptoBufSrc::seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which) + { + if(which == std::ios_base::in) + { + auto curPos = m_stream.tellg(); + //error on seek we may have read past the end already. Try resetting and seeking to the end first + if (curPos == pos_type(-1)) + { + m_stream.clear(); + m_stream.seekg(0, std::ios_base::end); + curPos = m_stream.tellg(); + } + + auto absPosition = ComputeAbsSeekPosition(off, dir, curPos); + size_t seekTo = static_cast<size_t>(absPosition); + size_t index = static_cast<size_t>(curPos); + + if(index == seekTo) + { + return curPos; + } + else if (seekTo < index) + { + m_cipher.Reset(); + m_stream.clear(); + m_stream.seekg(0); + m_isFinalized = false; + index = 0; + } + + CryptoBuffer cryptoBuffer; + while (m_cipher && index < seekTo && !m_isFinalized) + { + size_t max_read = std::min<size_t>(static_cast<size_t>(seekTo - index), m_bufferSize); + + Aws::Utils::Array<char> buf(max_read); + size_t readSize(0); + if(m_stream) + { + m_stream.read(buf.GetUnderlyingData(), max_read); + readSize = static_cast<size_t>(m_stream.gcount()); + } + + if (readSize > 0) + { + if (m_cipherMode == CipherMode::Encrypt) + { + cryptoBuffer = m_cipher.EncryptBuffer(CryptoBuffer(reinterpret_cast<unsigned char*>(buf.GetUnderlyingData()), readSize)); + } + else + { + cryptoBuffer = m_cipher.DecryptBuffer(CryptoBuffer(reinterpret_cast<unsigned char*>(buf.GetUnderlyingData()), readSize)); + } + } + else + { + if (m_cipherMode == CipherMode::Encrypt) + { + cryptoBuffer = m_cipher.FinalizeEncryption(); + } + else + { + cryptoBuffer = m_cipher.FinalizeDecryption(); + } + + m_isFinalized = true; + } + + index += cryptoBuffer.GetLength(); + } + + if (cryptoBuffer.GetLength() && m_cipher) + { + CryptoBuffer putBackArea(m_putBack); + + m_isBuf = CryptoBuffer({&putBackArea, &cryptoBuffer}); + //in the very unlikely case that the cipher had less output than the source stream. + assert(seekTo <= index); + size_t newBufferPos = index > seekTo ? cryptoBuffer.GetLength() - (index - seekTo) : cryptoBuffer.GetLength(); + char* baseBufPtr = reinterpret_cast<char*>(m_isBuf.GetUnderlyingData()); + setg(baseBufPtr, baseBufPtr + m_putBack + newBufferPos, baseBufPtr + m_isBuf.GetLength()); + + return pos_type(seekTo); + } + else if (seekTo == 0) + { + m_isBuf = CryptoBuffer(m_putBack); + char* end = reinterpret_cast<char*>(m_isBuf.GetUnderlyingData() + m_isBuf.GetLength()); + setg(end, end, end); + return pos_type(seekTo); + } + } + + return pos_type(off_type(-1)); + } + + SymmetricCryptoBufSrc::pos_type SymmetricCryptoBufSrc::seekpos(pos_type pos, std::ios_base::openmode which) + { + return seekoff(pos, std::ios_base::beg, which); + } + + SymmetricCryptoBufSrc::int_type SymmetricCryptoBufSrc::underflow() + { + if (!m_cipher || (m_isFinalized && gptr() >= egptr())) + { + return traits_type::eof(); + } + + if (gptr() < egptr()) + { + return traits_type::to_int_type(*gptr()); + } + + char* baseBufPtr = reinterpret_cast<char*>(m_isBuf.GetUnderlyingData()); + CryptoBuffer putBackArea(m_putBack); + + //eback is properly set after the first fill. So this guarantees we are on the second or later fill. + if (eback() == baseBufPtr) + { + //just fill in the last bit of the previous buffer into the put back area so that it has some data in it + memcpy(putBackArea.GetUnderlyingData(), egptr() - m_putBack, m_putBack); + } + + CryptoBuffer newDataBuf; + + while(!newDataBuf.GetLength() && !m_isFinalized) + { + Aws::Utils::Array<char> buf(m_bufferSize); + m_stream.read(buf.GetUnderlyingData(), m_bufferSize); + size_t readSize = static_cast<size_t>(m_stream.gcount()); + + if (readSize > 0) + { + if (m_cipherMode == CipherMode::Encrypt) + { + newDataBuf = m_cipher.EncryptBuffer(CryptoBuffer(reinterpret_cast<unsigned char*>(buf.GetUnderlyingData()), readSize)); + } + else + { + newDataBuf = m_cipher.DecryptBuffer(CryptoBuffer(reinterpret_cast<unsigned char*>(buf.GetUnderlyingData()), readSize)); + } + } + else + { + if (m_cipherMode == CipherMode::Encrypt) + { + newDataBuf = m_cipher.FinalizeEncryption(); + } + else + { + newDataBuf = m_cipher.FinalizeDecryption(); + } + + m_isFinalized = true; + } + } + + + if(newDataBuf.GetLength() > 0) + { + m_isBuf = CryptoBuffer({&putBackArea, &newDataBuf}); + + baseBufPtr = reinterpret_cast<char*>(m_isBuf.GetUnderlyingData()); + setg(baseBufPtr, baseBufPtr + m_putBack, baseBufPtr + m_isBuf.GetLength()); + + return traits_type::to_int_type(*gptr()); + } + + return traits_type::eof(); + } + + SymmetricCryptoBufSrc::off_type SymmetricCryptoBufSrc::ComputeAbsSeekPosition(off_type pos, std::ios_base::seekdir dir, std::fpos<FPOS_TYPE> curPos) + { + switch(dir) + { + case std::ios_base::beg: + return pos; + case std::ios_base::cur: + return m_stream.tellg() + pos; + case std::ios_base::end: + { + off_type absPos = m_stream.seekg(0, std::ios_base::end).tellg() - pos; + m_stream.seekg(curPos); + return absPos; + } + default: + assert(0); + return off_type(-1); + } + } + + void SymmetricCryptoBufSrc::FinalizeCipher() + { + if(m_cipher && !m_isFinalized) + { + if(m_cipherMode == CipherMode::Encrypt) + { + m_cipher.FinalizeEncryption(); + } + else + { + m_cipher.FinalizeDecryption(); + } + } + } + + SymmetricCryptoBufSink::SymmetricCryptoBufSink(Aws::OStream& stream, SymmetricCipher& cipher, CipherMode cipherMode, size_t bufferSize, int16_t blockOffset) + : + m_osBuf(bufferSize), m_cipher(cipher), m_stream(stream), m_cipherMode(cipherMode), m_isFinalized(false), m_blockOffset(blockOffset) + { + assert(m_blockOffset < 16 && m_blockOffset >= 0); + char* outputBase = reinterpret_cast<char*>(m_osBuf.GetUnderlyingData()); + setp(outputBase, outputBase + bufferSize - 1); + } + + SymmetricCryptoBufSink::~SymmetricCryptoBufSink() + { + FinalizeCiphersAndFlushSink(); + } + + void SymmetricCryptoBufSink::FinalizeCiphersAndFlushSink() + { + if(m_cipher && !m_isFinalized) + { + writeOutput(true); + } + } + + bool SymmetricCryptoBufSink::writeOutput(bool finalize) + { + if(!m_isFinalized) + { + CryptoBuffer cryptoBuf; + if (pptr() > pbase()) + { + if (m_cipherMode == CipherMode::Encrypt) + { + cryptoBuf = m_cipher.EncryptBuffer(CryptoBuffer(reinterpret_cast<unsigned char*>(pbase()), pptr() - pbase())); + } + else + { + cryptoBuf = m_cipher.DecryptBuffer(CryptoBuffer(reinterpret_cast<unsigned char*>(pbase()), pptr() - pbase())); + } + + pbump(-(static_cast<int>(pptr() - pbase()))); + } + if(finalize) + { + CryptoBuffer finalBuffer; + if (m_cipherMode == CipherMode::Encrypt) + { + finalBuffer = m_cipher.FinalizeEncryption(); + } + else + { + finalBuffer = m_cipher.FinalizeDecryption(); + } + if(cryptoBuf.GetLength()) + { + cryptoBuf = CryptoBuffer({&cryptoBuf, &finalBuffer}); + } + else + { + cryptoBuf = std::move(finalBuffer); + } + + m_isFinalized = true; + } + + if (m_cipher) + { + if(cryptoBuf.GetLength()) + { + //allow mid block decryption. We have to decrypt it, but we don't have to write it to the stream. + //the assumption here is that tellp() will always be 0 or >= 16 bytes. The block offset should only + //be the offset of the first block read. + size_t len = cryptoBuf.GetLength(); + size_t blockOffset = m_stream.tellp() > m_blockOffset ? 0 : m_blockOffset; + if (len > blockOffset) + { + m_stream.write(reinterpret_cast<char*>(cryptoBuf.GetUnderlyingData() + blockOffset), len - blockOffset); + m_blockOffset = 0; + } + else + { + m_blockOffset -= static_cast<int16_t>(len); + } + } + return true; + } + } + + return false; + } + + SymmetricCryptoBufSink::int_type SymmetricCryptoBufSink::overflow(int_type ch) + { + if(m_cipher && m_stream) + { + if(ch != traits_type::eof()) + { + *pptr() = (char)ch; + pbump(1); + } + + if(writeOutput(ch == traits_type::eof())) + { + return ch; + } + } + + return traits_type::eof(); + } + + int SymmetricCryptoBufSink::sync() + { + if(m_cipher && m_stream) + { + return writeOutput(false) ? 0 : -1; + } + + return -1; + } + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/CryptoStream.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/CryptoStream.cpp new file mode 100644 index 0000000000..2d645f7427 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/CryptoStream.cpp @@ -0,0 +1,52 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include <aws/core/utils/crypto/CryptoStream.h> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + static const char* CLASS_TAG = "Aws::Utils::Crypto::SymmetricCryptoStream"; + + SymmetricCryptoStream::SymmetricCryptoStream(Aws::IStream& src, CipherMode mode, SymmetricCipher& cipher, size_t bufSize) : + Aws::IOStream(m_cryptoBuf = Aws::New<SymmetricCryptoBufSrc>(CLASS_TAG, src, cipher, mode, bufSize)), m_hasOwnership(true) + { + } + + SymmetricCryptoStream::SymmetricCryptoStream(Aws::OStream& sink, CipherMode mode, SymmetricCipher& cipher, size_t bufSize, int16_t blockOffset) : + Aws::IOStream(m_cryptoBuf = Aws::New<SymmetricCryptoBufSink>(CLASS_TAG, sink, cipher, mode, bufSize, blockOffset)), m_hasOwnership(true) + { + } + + SymmetricCryptoStream::SymmetricCryptoStream(Aws::Utils::Crypto::SymmetricCryptoBufSrc& bufSrc) : + Aws::IOStream(&bufSrc), m_cryptoBuf(&bufSrc), m_hasOwnership(false) + { + } + + SymmetricCryptoStream::SymmetricCryptoStream(Aws::Utils::Crypto::SymmetricCryptoBufSink& bufSink) : + Aws::IOStream(&bufSink), m_cryptoBuf(&bufSink), m_hasOwnership(false) + { + } + + SymmetricCryptoStream::~SymmetricCryptoStream() + { + Finalize(); + + if(m_hasOwnership && m_cryptoBuf) + { + Aws::Delete(m_cryptoBuf); + } + } + + void SymmetricCryptoStream::Finalize() + { + assert(m_cryptoBuf); + m_cryptoBuf->Finalize(); + } + } + } +}
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/EncryptionMaterials.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/EncryptionMaterials.cpp new file mode 100644 index 0000000000..d000c86baa --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/EncryptionMaterials.cpp @@ -0,0 +1,19 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include <aws/core/utils/crypto/EncryptionMaterials.h> + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + //this is here to force the linker to behave correctly since this is an interface that will need to cross the dll + //boundary. + EncryptionMaterials::~EncryptionMaterials() + {} + } + } +}
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/KeyWrapAlgorithm.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/KeyWrapAlgorithm.cpp new file mode 100644 index 0000000000..b9e098775c --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/KeyWrapAlgorithm.cpp @@ -0,0 +1,68 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include <aws/core/utils/crypto/KeyWrapAlgorithm.h> +#include <aws/core/utils/HashingUtils.h> +#include <aws/core/utils/EnumParseOverflowContainer.h> +#include <aws/core/Globals.h> + +using namespace Aws::Utils; + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + namespace KeyWrapAlgorithmMapper + { + static const int keyWrapAlgorithm_KMS_HASH = HashingUtils::HashString("kms"); + static const int keyWrapAlgorithm_KMS_CONTEXT_HASH = HashingUtils::HashString("kms+context"); + static const int keyWrapAlgorithm_KeyWrap_HASH = HashingUtils::HashString("AESWrap"); + static const int keyWrapAlgorithm_AES_GCM_HASH = HashingUtils::HashString("AES/GCM"); + + KeyWrapAlgorithm GetKeyWrapAlgorithmForName(const Aws::String& name) + { + int hashcode = HashingUtils::HashString(name.c_str()); + if (hashcode == keyWrapAlgorithm_KMS_HASH) + { + return KeyWrapAlgorithm::KMS; + } + else if (hashcode == keyWrapAlgorithm_KMS_CONTEXT_HASH) + { + return KeyWrapAlgorithm::KMS_CONTEXT; + } + else if (hashcode == keyWrapAlgorithm_KeyWrap_HASH) + { + return KeyWrapAlgorithm::AES_KEY_WRAP; + } + else if (hashcode == keyWrapAlgorithm_AES_GCM_HASH) + { + return KeyWrapAlgorithm::AES_GCM; + } + assert(0); + return KeyWrapAlgorithm::NONE; + } + + Aws::String GetNameForKeyWrapAlgorithm(KeyWrapAlgorithm enumValue) + { + switch (enumValue) + { + case KeyWrapAlgorithm::KMS: + return "kms"; + case KeyWrapAlgorithm::KMS_CONTEXT: + return "kms+context"; + case KeyWrapAlgorithm::AES_KEY_WRAP: + return "AESWrap"; + case KeyWrapAlgorithm::AES_GCM: + return "AES/GCM"; + default: + assert(0); + } + return ""; + } + }//namespace KeyWrapAlgorithmMapper + }//namespace Crypto + }//namespace Utils +}//namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/MD5.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/MD5.cpp new file mode 100644 index 0000000000..bf14ace1ad --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/MD5.cpp @@ -0,0 +1,31 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#include <aws/core/utils/crypto/MD5.h> +#include <aws/core/utils/Outcome.h> +#include <aws/core/utils/crypto/Factories.h> + +using namespace Aws::Utils::Crypto; + + +MD5::MD5() : + m_hashImpl(CreateMD5Implementation()) +{ +} + +MD5::~MD5() +{ +} + +HashResult MD5::Calculate(const Aws::String& str) +{ + return m_hashImpl->Calculate(str); +} + +HashResult MD5::Calculate(Aws::IStream& stream) +{ + return m_hashImpl->Calculate(stream); +}
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Sha256.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Sha256.cpp new file mode 100644 index 0000000000..178df00d37 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Sha256.cpp @@ -0,0 +1,30 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#include <aws/core/utils/crypto/Sha256.h> +#include <aws/core/utils/Outcome.h> +#include <aws/core/utils/crypto/Factories.h> + +using namespace Aws::Utils::Crypto; + +Sha256::Sha256() : + m_hashImpl(CreateSha256Implementation()) +{ +} + +Sha256::~Sha256() +{ +} + +HashResult Sha256::Calculate(const Aws::String& str) +{ + return m_hashImpl->Calculate(str); +} + +HashResult Sha256::Calculate(Aws::IStream& stream) +{ + return m_hashImpl->Calculate(stream); +}
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Sha256HMAC.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Sha256HMAC.cpp new file mode 100644 index 0000000000..ecc1f06529 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Sha256HMAC.cpp @@ -0,0 +1,34 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#include <aws/core/utils/crypto/Sha256HMAC.h> +#include <aws/core/utils/crypto/Factories.h> +#include <aws/core/utils/Outcome.h> + +namespace Aws +{ +namespace Utils +{ +namespace Crypto +{ + +Sha256HMAC::Sha256HMAC() : + m_hmacImpl(CreateSha256HMACImplementation()) +{ +} + +Sha256HMAC::~Sha256HMAC() +{ +} + +HashResult Sha256HMAC::Calculate(const Aws::Utils::ByteBuffer& toSign, const Aws::Utils::ByteBuffer& secret) +{ + return m_hmacImpl->Calculate(toSign, secret); +} + +} // namespace Crypto +} // namespace Utils +} // namespace Aws
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/factory/Factories.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/factory/Factories.cpp new file mode 100644 index 0000000000..bff0382241 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/factory/Factories.cpp @@ -0,0 +1,895 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#include <aws/core/utils/crypto/Factories.h> +#include <aws/core/utils/crypto/Hash.h> +#include <aws/core/utils/crypto/HMAC.h> + +#if ENABLE_BCRYPT_ENCRYPTION + #error #include <aws/core/utils/crypto/bcrypt/CryptoImpl.h> +#elif ENABLE_OPENSSL_ENCRYPTION + #include <aws/core/utils/crypto/openssl/CryptoImpl.h> +#elif ENABLE_COMMONCRYPTO_ENCRYPTION + #error #include <aws/core/utils/crypto/commoncrypto/CryptoImpl.h> + #include <aws/core/utils/logging/LogMacros.h> +#else + // if you don't have any encryption you still need to pull in the interface definitions + #include <aws/core/utils/crypto/Hash.h> + #include <aws/core/utils/crypto/HMAC.h> + #include <aws/core/utils/crypto/Cipher.h> + #include <aws/core/utils/crypto/SecureRandom.h> + #define NO_ENCRYPTION +#endif + +using namespace Aws::Utils; +using namespace Aws::Utils::Crypto; + +static const char *s_allocationTag = "CryptoFactory"; + +static std::shared_ptr<HashFactory>& GetMD5Factory() +{ + static std::shared_ptr<HashFactory> s_MD5Factory(nullptr); + return s_MD5Factory; +} + +static std::shared_ptr<HashFactory>& GetSha256Factory() +{ + static std::shared_ptr<HashFactory> s_Sha256Factory(nullptr); + return s_Sha256Factory; +} + +static std::shared_ptr<HMACFactory>& GetSha256HMACFactory() +{ + static std::shared_ptr<HMACFactory> s_Sha256HMACFactory(nullptr); + return s_Sha256HMACFactory; +} + +static std::shared_ptr<SymmetricCipherFactory>& GetAES_CBCFactory() +{ + static std::shared_ptr<SymmetricCipherFactory> s_AES_CBCFactory(nullptr); + return s_AES_CBCFactory; +} + +static std::shared_ptr<SymmetricCipherFactory>& GetAES_CTRFactory() +{ + static std::shared_ptr<SymmetricCipherFactory> s_AES_CTRFactory(nullptr); + return s_AES_CTRFactory; +} + +static std::shared_ptr<SymmetricCipherFactory>& GetAES_GCMFactory() +{ + static std::shared_ptr<SymmetricCipherFactory> s_AES_GCMFactory(nullptr); + return s_AES_GCMFactory; +} + +static std::shared_ptr<SymmetricCipherFactory>& GetAES_KeyWrapFactory() +{ + static std::shared_ptr<SymmetricCipherFactory> s_AES_KeyWrapFactory(nullptr); + return s_AES_KeyWrapFactory; +} + +static std::shared_ptr<SecureRandomFactory>& GetSecureRandomFactory() +{ + static std::shared_ptr<SecureRandomFactory> s_SecureRandomFactory(nullptr); + return s_SecureRandomFactory; +} + +static std::shared_ptr<SecureRandomBytes>& GetSecureRandom() +{ + static std::shared_ptr<SecureRandomBytes> s_SecureRandom(nullptr); + return s_SecureRandom; +} + +static bool s_InitCleanupOpenSSLFlag(false); + +class DefaultMD5Factory : public HashFactory +{ +public: + std::shared_ptr<Hash> CreateImplementation() const override + { +#if ENABLE_BCRYPT_ENCRYPTION + return Aws::MakeShared<MD5BcryptImpl>(s_allocationTag); +#elif ENABLE_OPENSSL_ENCRYPTION + return Aws::MakeShared<MD5OpenSSLImpl>(s_allocationTag); +#elif ENABLE_COMMONCRYPTO_ENCRYPTION + return Aws::MakeShared<MD5CommonCryptoImpl>(s_allocationTag); +#else + return nullptr; +#endif + } + + /** + * Opportunity to make any static initialization calls you need to make. + * Will only be called once. + */ + void InitStaticState() override + { +#if ENABLE_OPENSSL_ENCRYPTION + if(s_InitCleanupOpenSSLFlag) + { + OpenSSL::getTheLights.EnterRoom(&OpenSSL::init_static_state); + } +#endif + } + + /** + * Opportunity to make any static cleanup calls you need to make. + * will only be called at the end of the application. + */ + void CleanupStaticState() override + { +#if ENABLE_OPENSSL_ENCRYPTION + if(s_InitCleanupOpenSSLFlag) + { + OpenSSL::getTheLights.LeaveRoom(&OpenSSL::cleanup_static_state); + } +#endif + } +}; + +class DefaultSHA256Factory : public HashFactory +{ +public: + std::shared_ptr<Hash> CreateImplementation() const override + { +#if ENABLE_BCRYPT_ENCRYPTION + return Aws::MakeShared<Sha256BcryptImpl>(s_allocationTag); +#elif ENABLE_OPENSSL_ENCRYPTION + return Aws::MakeShared<Sha256OpenSSLImpl>(s_allocationTag); +#elif ENABLE_COMMONCRYPTO_ENCRYPTION + return Aws::MakeShared<Sha256CommonCryptoImpl>(s_allocationTag); +#else + return nullptr; +#endif + } + + /** + * Opportunity to make any static initialization calls you need to make. + * Will only be called once. + */ + void InitStaticState() override + { +#if ENABLE_OPENSSL_ENCRYPTION + if(s_InitCleanupOpenSSLFlag) + { + OpenSSL::getTheLights.EnterRoom(&OpenSSL::init_static_state); + } +#endif + } + + /** + * Opportunity to make any static cleanup calls you need to make. + * will only be called at the end of the application. + */ + void CleanupStaticState() override + { +#if ENABLE_OPENSSL_ENCRYPTION + if(s_InitCleanupOpenSSLFlag) + { + OpenSSL::getTheLights.LeaveRoom(&OpenSSL::cleanup_static_state); + } +#endif + } +}; + +class DefaultSHA256HmacFactory : public HMACFactory +{ +public: + std::shared_ptr<Aws::Utils::Crypto::HMAC> CreateImplementation() const override + { +#if ENABLE_BCRYPT_ENCRYPTION + return Aws::MakeShared<Sha256HMACBcryptImpl>(s_allocationTag); +#elif ENABLE_OPENSSL_ENCRYPTION + return Aws::MakeShared<Sha256HMACOpenSSLImpl>(s_allocationTag); +#elif ENABLE_COMMONCRYPTO_ENCRYPTION + return Aws::MakeShared<Sha256HMACCommonCryptoImpl>(s_allocationTag); +#else + return nullptr; +#endif + } + + /** + * Opportunity to make any static initialization calls you need to make. + * Will only be called once. + */ + void InitStaticState() override + { +#if ENABLE_OPENSSL_ENCRYPTION + if(s_InitCleanupOpenSSLFlag) + { + OpenSSL::getTheLights.EnterRoom(&OpenSSL::init_static_state); + } +#endif + } + + /** + * Opportunity to make any static cleanup calls you need to make. + * will only be called at the end of the application. + */ + void CleanupStaticState() override + { +#if ENABLE_OPENSSL_ENCRYPTION + if(s_InitCleanupOpenSSLFlag) + { + OpenSSL::getTheLights.LeaveRoom(&OpenSSL::cleanup_static_state); + } +#endif + } +}; + + +class DefaultAES_CBCFactory : public SymmetricCipherFactory +{ +public: + std::shared_ptr<SymmetricCipher> CreateImplementation(const CryptoBuffer& key) const override + { +#if ENABLE_BCRYPT_ENCRYPTION + return Aws::MakeShared<AES_CBC_Cipher_BCrypt>(s_allocationTag, key); +#elif ENABLE_OPENSSL_ENCRYPTION + return Aws::MakeShared<AES_CBC_Cipher_OpenSSL>(s_allocationTag, key); +#elif ENABLE_COMMONCRYPTO_ENCRYPTION + return Aws::MakeShared<AES_CBC_Cipher_CommonCrypto>(s_allocationTag, key); +#else + AWS_UNREFERENCED_PARAM(key); + return nullptr; +#endif + } + /** + * Factory method. Returns cipher implementation. See the SymmetricCipher class for more details. + */ + std::shared_ptr<SymmetricCipher> CreateImplementation(const CryptoBuffer& key, const CryptoBuffer& iv, const CryptoBuffer&, const CryptoBuffer&) const override + { +#if ENABLE_BCRYPT_ENCRYPTION + return Aws::MakeShared<AES_CBC_Cipher_BCrypt>(s_allocationTag, key, iv); +#elif ENABLE_OPENSSL_ENCRYPTION + return Aws::MakeShared<AES_CBC_Cipher_OpenSSL>(s_allocationTag, key, iv); +#elif ENABLE_COMMONCRYPTO_ENCRYPTION + return Aws::MakeShared<AES_CBC_Cipher_CommonCrypto>(s_allocationTag, key, iv); +#else + AWS_UNREFERENCED_PARAM(key); + AWS_UNREFERENCED_PARAM(iv); + + return nullptr; +#endif + } + /** + * Factory method. Returns cipher implementation. See the SymmetricCipher class for more details. + */ + std::shared_ptr<SymmetricCipher> CreateImplementation(CryptoBuffer&& key, CryptoBuffer&& iv, CryptoBuffer&&, CryptoBuffer&&) const override + { +#if ENABLE_BCRYPT_ENCRYPTION + return Aws::MakeShared<AES_CBC_Cipher_BCrypt>(s_allocationTag, key, iv); +#elif ENABLE_OPENSSL_ENCRYPTION + return Aws::MakeShared<AES_CBC_Cipher_OpenSSL>(s_allocationTag, key, iv); +#elif ENABLE_COMMONCRYPTO_ENCRYPTION + return Aws::MakeShared<AES_CBC_Cipher_CommonCrypto>(s_allocationTag, key, iv); +#else + AWS_UNREFERENCED_PARAM(key); + AWS_UNREFERENCED_PARAM(iv); + + return nullptr; +#endif + } + + /** + * Opportunity to make any static initialization calls you need to make. + * Will only be called once. + */ + void InitStaticState() override + { +#if ENABLE_OPENSSL_ENCRYPTION + if(s_InitCleanupOpenSSLFlag) + { + OpenSSL::getTheLights.EnterRoom(&OpenSSL::init_static_state); + } +#endif + } + + /** + * Opportunity to make any static cleanup calls you need to make. + * will only be called at the end of the application. + */ + void CleanupStaticState() override + { +#if ENABLE_OPENSSL_ENCRYPTION + if(s_InitCleanupOpenSSLFlag) + { + OpenSSL::getTheLights.LeaveRoom(&OpenSSL::cleanup_static_state); + } +#endif + } +}; + +class DefaultAES_CTRFactory : public SymmetricCipherFactory +{ +public: + std::shared_ptr<SymmetricCipher> CreateImplementation(const CryptoBuffer& key) const override + { +#if ENABLE_BCRYPT_ENCRYPTION + return Aws::MakeShared<AES_CTR_Cipher_BCrypt>(s_allocationTag, key); +#elif ENABLE_OPENSSL_ENCRYPTION + return Aws::MakeShared<AES_CTR_Cipher_OpenSSL>(s_allocationTag, key); +#elif ENABLE_COMMONCRYPTO_ENCRYPTION + return Aws::MakeShared<AES_CTR_Cipher_CommonCrypto>(s_allocationTag, key); +#else + AWS_UNREFERENCED_PARAM(key); + return nullptr; +#endif + } + /** + * Factory method. Returns cipher implementation. See the SymmetricCipher class for more details. + */ + std::shared_ptr<SymmetricCipher> CreateImplementation(const CryptoBuffer& key, const CryptoBuffer& iv, const CryptoBuffer&, const CryptoBuffer&) const override + { +#if ENABLE_BCRYPT_ENCRYPTION + return Aws::MakeShared<AES_CTR_Cipher_BCrypt>(s_allocationTag, key, iv); +#elif ENABLE_OPENSSL_ENCRYPTION + return Aws::MakeShared<AES_CTR_Cipher_OpenSSL>(s_allocationTag, key, iv); +#elif ENABLE_COMMONCRYPTO_ENCRYPTION + return Aws::MakeShared<AES_CTR_Cipher_CommonCrypto>(s_allocationTag, key, iv); +#else + AWS_UNREFERENCED_PARAM(key); + AWS_UNREFERENCED_PARAM(iv); + + return nullptr; +#endif + } + /** + * Factory method. Returns cipher implementation. See the SymmetricCipher class for more details. + */ + std::shared_ptr<SymmetricCipher> CreateImplementation(CryptoBuffer&& key, CryptoBuffer&& iv, CryptoBuffer&&, CryptoBuffer&&) const override + { +#if ENABLE_BCRYPT_ENCRYPTION + return Aws::MakeShared<AES_CTR_Cipher_BCrypt>(s_allocationTag, key, iv); +#elif ENABLE_OPENSSL_ENCRYPTION + return Aws::MakeShared<AES_CTR_Cipher_OpenSSL>(s_allocationTag, key, iv); +#elif ENABLE_COMMONCRYPTO_ENCRYPTION + return Aws::MakeShared<AES_CTR_Cipher_CommonCrypto>(s_allocationTag, key, iv); +#else + AWS_UNREFERENCED_PARAM(key); + AWS_UNREFERENCED_PARAM(iv); + + return nullptr; +#endif + } + + /** + * Opportunity to make any static initialization calls you need to make. + * Will only be called once. + */ + void InitStaticState() override + { +#if ENABLE_OPENSSL_ENCRYPTION + if(s_InitCleanupOpenSSLFlag) + { + OpenSSL::getTheLights.EnterRoom(&OpenSSL::init_static_state); + } +#endif + } + + /** + * Opportunity to make any static cleanup calls you need to make. + * will only be called at the end of the application. + */ + void CleanupStaticState() override + { +#if ENABLE_OPENSSL_ENCRYPTION + if(s_InitCleanupOpenSSLFlag) + { + OpenSSL::getTheLights.LeaveRoom(&OpenSSL::cleanup_static_state); + } +#endif + } +}; + +class DefaultAES_GCMFactory : public SymmetricCipherFactory +{ +public: + std::shared_ptr<SymmetricCipher> CreateImplementation(const CryptoBuffer& key) const override + { +#if ENABLE_BCRYPT_ENCRYPTION + return Aws::MakeShared<AES_GCM_Cipher_BCrypt>(s_allocationTag, key); +#elif ENABLE_OPENSSL_ENCRYPTION + return Aws::MakeShared<AES_GCM_Cipher_OpenSSL>(s_allocationTag, key); +#elif ENABLE_COMMONCRYPTO_ENCRYPTION + return Aws::MakeShared<AES_GCM_Cipher_CommonCrypto>(s_allocationTag, key); +#else + AWS_UNREFERENCED_PARAM(key); + + return nullptr; +#endif + } + + std::shared_ptr<SymmetricCipher> CreateImplementation(const CryptoBuffer& key, const CryptoBuffer* aad) const override + { +#if ENABLE_BCRYPT_ENCRYPTION + return Aws::MakeShared<AES_GCM_Cipher_BCrypt>(s_allocationTag, key, aad); +#elif ENABLE_OPENSSL_ENCRYPTION + return Aws::MakeShared<AES_GCM_Cipher_OpenSSL>(s_allocationTag, key, aad); +#elif ENABLE_COMMONCRYPTO_ENCRYPTION + return Aws::MakeShared<AES_GCM_Cipher_CommonCrypto>(s_allocationTag, key, aad); +#else + AWS_UNREFERENCED_PARAM(key); + AWS_UNREFERENCED_PARAM(aad); + return nullptr; +#endif + } + + /** + * Factory method. Returns cipher implementation. See the SymmetricCipher class for more details. + */ + std::shared_ptr<SymmetricCipher> CreateImplementation(const CryptoBuffer& key, const CryptoBuffer& iv, const CryptoBuffer& tag, const CryptoBuffer& aad) const override + { +#if ENABLE_BCRYPT_ENCRYPTION + return Aws::MakeShared<AES_GCM_Cipher_BCrypt>(s_allocationTag, key, iv, tag, aad); +#elif ENABLE_OPENSSL_ENCRYPTION + return Aws::MakeShared<AES_GCM_Cipher_OpenSSL>(s_allocationTag, key, iv, tag, aad); +#elif ENABLE_COMMONCRYPTO_ENCRYPTION + return Aws::MakeShared<AES_GCM_Cipher_CommonCrypto>(s_allocationTag, key, iv, tag, aad); +#else + AWS_UNREFERENCED_PARAM(key); + AWS_UNREFERENCED_PARAM(iv); + AWS_UNREFERENCED_PARAM(tag); + AWS_UNREFERENCED_PARAM(aad); + return nullptr; +#endif + } + /** + * Factory method. Returns cipher implementation. See the SymmetricCipher class for more details. + */ + std::shared_ptr<SymmetricCipher> CreateImplementation(CryptoBuffer&& key, CryptoBuffer&& iv, CryptoBuffer&& tag, CryptoBuffer&& aad) const override + { +#if ENABLE_BCRYPT_ENCRYPTION + return Aws::MakeShared<AES_GCM_Cipher_BCrypt>(s_allocationTag, std::move(key), std::move(iv), std::move(tag), std::move(aad)); +#elif ENABLE_OPENSSL_ENCRYPTION + return Aws::MakeShared<AES_GCM_Cipher_OpenSSL>(s_allocationTag, std::move(key), std::move(iv), std::move(tag), std::move(aad)); +#elif ENABLE_COMMONCRYPTO_ENCRYPTION + return Aws::MakeShared<AES_GCM_Cipher_CommonCrypto>(s_allocationTag, std::move(key), std::move(iv), std::move(tag), std::move(aad)); +#else + AWS_UNREFERENCED_PARAM(key); + AWS_UNREFERENCED_PARAM(iv); + AWS_UNREFERENCED_PARAM(tag); + AWS_UNREFERENCED_PARAM(aad); + return nullptr; +#endif + } + + /** + * Opportunity to make any static initialization calls you need to make. + * Will only be called once. + */ + void InitStaticState() override + { +#if ENABLE_OPENSSL_ENCRYPTION + if(s_InitCleanupOpenSSLFlag) + { + OpenSSL::getTheLights.EnterRoom(&OpenSSL::init_static_state); + } +#endif + } + + /** + * Opportunity to make any static cleanup calls you need to make. + * will only be called at the end of the application. + */ + void CleanupStaticState() override + { +#if ENABLE_OPENSSL_ENCRYPTION + if(s_InitCleanupOpenSSLFlag) + { + OpenSSL::getTheLights.LeaveRoom(&OpenSSL::cleanup_static_state); + } +#endif + } +}; + +class DefaultAES_KeyWrapFactory : public SymmetricCipherFactory +{ +public: + std::shared_ptr<SymmetricCipher> CreateImplementation(const CryptoBuffer& key) const override + { +#if ENABLE_BCRYPT_ENCRYPTION + return Aws::MakeShared<AES_KeyWrap_Cipher_BCrypt>(s_allocationTag, key); +#elif ENABLE_OPENSSL_ENCRYPTION + return Aws::MakeShared<AES_KeyWrap_Cipher_OpenSSL>(s_allocationTag, key); +#elif ENABLE_COMMONCRYPTO_ENCRYPTION + return Aws::MakeShared<AES_KeyWrap_Cipher_CommonCrypto>(s_allocationTag, key); +#else + AWS_UNREFERENCED_PARAM(key); + return nullptr; +#endif + } + /** + * Factory method. Returns cipher implementation. See the SymmetricCipher class for more details. + */ + std::shared_ptr<SymmetricCipher> CreateImplementation(const CryptoBuffer& key, const CryptoBuffer& iv, const CryptoBuffer& tag, const CryptoBuffer&) const override + { + AWS_UNREFERENCED_PARAM(key); + AWS_UNREFERENCED_PARAM(iv); + AWS_UNREFERENCED_PARAM(tag); + return nullptr; + } + /** + * Factory method. Returns cipher implementation. See the SymmetricCipher class for more details. + */ + std::shared_ptr<SymmetricCipher> CreateImplementation(CryptoBuffer&& key, CryptoBuffer&& iv, CryptoBuffer&& tag, CryptoBuffer&&) const override + { + AWS_UNREFERENCED_PARAM(key); + AWS_UNREFERENCED_PARAM(iv); + AWS_UNREFERENCED_PARAM(tag); + return nullptr; + } + + /** + * Opportunity to make any static initialization calls you need to make. + * Will only be called once. + */ + void InitStaticState() override + { +#if ENABLE_OPENSSL_ENCRYPTION + if (s_InitCleanupOpenSSLFlag) + { + OpenSSL::getTheLights.EnterRoom(&OpenSSL::init_static_state); + } +#endif + } + + /** + * Opportunity to make any static cleanup calls you need to make. + * will only be called at the end of the application. + */ + void CleanupStaticState() override + { +#if ENABLE_OPENSSL_ENCRYPTION + if (s_InitCleanupOpenSSLFlag) + { + OpenSSL::getTheLights.LeaveRoom(&OpenSSL::cleanup_static_state); + } +#endif + } +}; + +class DefaultSecureRandFactory : public SecureRandomFactory +{ + /** + * Factory method. Returns SecureRandom implementation. + */ + std::shared_ptr<SecureRandomBytes> CreateImplementation() const override + { +#if ENABLE_BCRYPT_ENCRYPTION + return Aws::MakeShared<SecureRandomBytes_BCrypt>(s_allocationTag); +#elif ENABLE_OPENSSL_ENCRYPTION + return Aws::MakeShared<SecureRandomBytes_OpenSSLImpl>(s_allocationTag); +#elif ENABLE_COMMONCRYPTO_ENCRYPTION + return Aws::MakeShared<SecureRandomBytes_CommonCrypto>(s_allocationTag); +#else + return nullptr; +#endif + } + + /** + * Opportunity to make any static initialization calls you need to make. + * Will only be called once. + */ + void InitStaticState() override + { +#if ENABLE_OPENSSL_ENCRYPTION + if(s_InitCleanupOpenSSLFlag) + { + OpenSSL::getTheLights.EnterRoom(&OpenSSL::init_static_state); + } +#endif + } + + /** + * Opportunity to make any static cleanup calls you need to make. + * will only be called at the end of the application. + */ + void CleanupStaticState() override + { +#if ENABLE_OPENSSL_ENCRYPTION + if(s_InitCleanupOpenSSLFlag) + { + OpenSSL::getTheLights.LeaveRoom(&OpenSSL::cleanup_static_state); + } +#endif + } +}; + +void Aws::Utils::Crypto::SetInitCleanupOpenSSLFlag(bool initCleanupFlag) +{ + s_InitCleanupOpenSSLFlag = initCleanupFlag; +} + +void Aws::Utils::Crypto::InitCrypto() +{ + if(GetMD5Factory()) + { + GetMD5Factory()->InitStaticState(); + } + else + { + GetMD5Factory() = Aws::MakeShared<DefaultMD5Factory>(s_allocationTag); + GetMD5Factory()->InitStaticState(); + } + + if(GetSha256Factory()) + { + GetSha256Factory()->InitStaticState(); + } + else + { + GetSha256Factory() = Aws::MakeShared<DefaultSHA256Factory>(s_allocationTag); + GetSha256Factory()->InitStaticState(); + } + + if(GetSha256HMACFactory()) + { + GetSha256HMACFactory()->InitStaticState(); + } + else + { + GetSha256HMACFactory() = Aws::MakeShared<DefaultSHA256HmacFactory>(s_allocationTag); + GetSha256HMACFactory()->InitStaticState(); + } + + if(GetAES_CBCFactory()) + { + GetAES_CBCFactory()->InitStaticState(); + } + else + { + GetAES_CBCFactory() = Aws::MakeShared<DefaultAES_CBCFactory>(s_allocationTag); + GetAES_CBCFactory()->InitStaticState(); + } + + if(GetAES_CTRFactory()) + { + GetAES_CTRFactory()->InitStaticState(); + } + else + { + GetAES_CTRFactory() = Aws::MakeShared<DefaultAES_CTRFactory>(s_allocationTag); + GetAES_CTRFactory()->InitStaticState(); + } + + if(GetAES_GCMFactory()) + { + GetAES_GCMFactory()->InitStaticState(); + } + else + { + GetAES_GCMFactory() = Aws::MakeShared<DefaultAES_GCMFactory>(s_allocationTag); + GetAES_GCMFactory()->InitStaticState(); + } + + if (!GetAES_KeyWrapFactory()) + { + GetAES_KeyWrapFactory() = Aws::MakeShared<DefaultAES_KeyWrapFactory>(s_allocationTag); + } + GetAES_KeyWrapFactory()->InitStaticState(); + + if(GetSecureRandomFactory()) + { + GetSecureRandomFactory()->InitStaticState(); + } + else + { + GetSecureRandomFactory() = Aws::MakeShared<DefaultSecureRandFactory>(s_allocationTag); + GetSecureRandomFactory()->InitStaticState(); + } + + GetSecureRandom() = GetSecureRandomFactory()->CreateImplementation(); +} + +void Aws::Utils::Crypto::CleanupCrypto() +{ + if(GetMD5Factory()) + { + GetMD5Factory()->CleanupStaticState(); + GetMD5Factory() = nullptr; + } + + if(GetSha256Factory()) + { + GetSha256Factory()->CleanupStaticState(); + GetSha256Factory() = nullptr; + } + + if(GetSha256HMACFactory()) + { + GetSha256HMACFactory()->CleanupStaticState(); + GetSha256HMACFactory() = nullptr; + } + + if(GetAES_CBCFactory()) + { + GetAES_CBCFactory()->CleanupStaticState(); + GetAES_CBCFactory() = nullptr; + } + + if(GetAES_CTRFactory()) + { + GetAES_CTRFactory()->CleanupStaticState(); + GetAES_CTRFactory() = nullptr; + } + + if(GetAES_GCMFactory()) + { + GetAES_GCMFactory()->CleanupStaticState(); + GetAES_GCMFactory() = nullptr; + } + + if(GetAES_KeyWrapFactory()) + { + GetAES_KeyWrapFactory()->CleanupStaticState(); + GetAES_KeyWrapFactory() = nullptr; + } + + if(GetSecureRandomFactory()) + { + GetSecureRandom() = nullptr; + GetSecureRandomFactory()->CleanupStaticState(); + GetSecureRandomFactory() = nullptr; + } +} + +void Aws::Utils::Crypto::SetMD5Factory(const std::shared_ptr<HashFactory>& factory) +{ + GetMD5Factory() = factory; +} + +void Aws::Utils::Crypto::SetSha256Factory(const std::shared_ptr<HashFactory>& factory) +{ + GetSha256Factory() = factory; +} + +void Aws::Utils::Crypto::SetSha256HMACFactory(const std::shared_ptr<HMACFactory>& factory) +{ + GetSha256HMACFactory() = factory; +} + +void Aws::Utils::Crypto::SetAES_CBCFactory(const std::shared_ptr<SymmetricCipherFactory>& factory) +{ + GetAES_CBCFactory() = factory; +} + +void Aws::Utils::Crypto::SetAES_CTRFactory(const std::shared_ptr<SymmetricCipherFactory>& factory) +{ + GetAES_CTRFactory() = factory; +} + +void Aws::Utils::Crypto::SetAES_GCMFactory(const std::shared_ptr<SymmetricCipherFactory>& factory) +{ + GetAES_GCMFactory() = factory; +} + +void Aws::Utils::Crypto::SetAES_KeyWrapFactory(const std::shared_ptr<SymmetricCipherFactory>& factory) +{ + GetAES_KeyWrapFactory() = factory; +} + +void Aws::Utils::Crypto::SetSecureRandomFactory(const std::shared_ptr<SecureRandomFactory>& factory) +{ + GetSecureRandomFactory() = factory; +} + +std::shared_ptr<Hash> Aws::Utils::Crypto::CreateMD5Implementation() +{ + return GetMD5Factory()->CreateImplementation(); +} + +std::shared_ptr<Hash> Aws::Utils::Crypto::CreateSha256Implementation() +{ + return GetSha256Factory()->CreateImplementation(); +} + +std::shared_ptr<Aws::Utils::Crypto::HMAC> Aws::Utils::Crypto::CreateSha256HMACImplementation() +{ + return GetSha256HMACFactory()->CreateImplementation(); +} + +#ifdef _WIN32 +#pragma warning( push ) +#pragma warning( disable : 4702 ) +#endif + +std::shared_ptr<SymmetricCipher> Aws::Utils::Crypto::CreateAES_CBCImplementation(const CryptoBuffer& key) +{ +#ifdef NO_SYMMETRIC_ENCRYPTION + return nullptr; +#endif + return GetAES_CBCFactory()->CreateImplementation(key); +} + +std::shared_ptr<SymmetricCipher> Aws::Utils::Crypto::CreateAES_CBCImplementation(const CryptoBuffer& key, const CryptoBuffer& iv) +{ +#ifdef NO_SYMMETRIC_ENCRYPTION + return nullptr; +#endif + return GetAES_CBCFactory()->CreateImplementation(key, iv); +} + +std::shared_ptr<SymmetricCipher> Aws::Utils::Crypto::CreateAES_CBCImplementation(CryptoBuffer&& key, CryptoBuffer&& iv) +{ +#ifdef NO_SYMMETRIC_ENCRYPTION + return nullptr; +#endif + return GetAES_CBCFactory()->CreateImplementation(std::move(key), std::move(iv)); +} + +std::shared_ptr<SymmetricCipher> Aws::Utils::Crypto::CreateAES_CTRImplementation(const CryptoBuffer& key) +{ +#ifdef NO_SYMMETRIC_ENCRYPTION + return nullptr; +#endif + return GetAES_CTRFactory()->CreateImplementation(key); +} + +std::shared_ptr<SymmetricCipher> Aws::Utils::Crypto::CreateAES_CTRImplementation(const CryptoBuffer& key, const CryptoBuffer& iv) +{ +#ifdef NO_SYMMETRIC_ENCRYPTION + return nullptr; +#endif + return GetAES_CTRFactory()->CreateImplementation(key, iv); +} + +std::shared_ptr<SymmetricCipher> Aws::Utils::Crypto::CreateAES_CTRImplementation(CryptoBuffer&& key, CryptoBuffer&& iv) +{ +#ifdef NO_SYMMETRIC_ENCRYPTION + return nullptr; +#endif + return GetAES_CTRFactory()->CreateImplementation(std::move(key), std::move(iv)); +} + +std::shared_ptr<SymmetricCipher> Aws::Utils::Crypto::CreateAES_GCMImplementation(const CryptoBuffer& key) +{ +#ifdef NO_SYMMETRIC_ENCRYPTION + return nullptr; +#endif + return GetAES_GCMFactory()->CreateImplementation(key); +} + +std::shared_ptr<SymmetricCipher> Aws::Utils::Crypto::CreateAES_GCMImplementation(const CryptoBuffer& key, const CryptoBuffer* aad) +{ +#ifdef NO_SYMMETRIC_ENCRYPTION + return nullptr; +#endif + return GetAES_GCMFactory()->CreateImplementation(key, aad); +} + +std::shared_ptr<SymmetricCipher> Aws::Utils::Crypto::CreateAES_GCMImplementation(const CryptoBuffer& key, const CryptoBuffer& iv, const CryptoBuffer& tag, const CryptoBuffer& aad) +{ +#ifdef NO_SYMMETRIC_ENCRYPTION + return nullptr; +#endif + return GetAES_GCMFactory()->CreateImplementation(key, iv, tag, aad); +} + +std::shared_ptr<SymmetricCipher> Aws::Utils::Crypto::CreateAES_GCMImplementation(CryptoBuffer&& key, CryptoBuffer&& iv, CryptoBuffer&& tag, CryptoBuffer&& aad) +{ +#ifdef NO_SYMMETRIC_ENCRYPTION + return nullptr; +#endif + return GetAES_GCMFactory()->CreateImplementation(std::move(key), std::move(iv), std::move(tag), std::move(aad)); +} + +std::shared_ptr<SymmetricCipher> Aws::Utils::Crypto::CreateAES_KeyWrapImplementation(const CryptoBuffer& key) +{ +#ifdef NO_SYMMETRIC_ENCRYPTION + return nullptr; +#endif + return GetAES_KeyWrapFactory()->CreateImplementation(key); +} + +#ifdef _WIN32 +#pragma warning(pop) +#endif + +std::shared_ptr<SecureRandomBytes> Aws::Utils::Crypto::CreateSecureRandomBytesImplementation() +{ + return GetSecureRandom(); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/openssl/CryptoImpl.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/openssl/CryptoImpl.cpp new file mode 100644 index 0000000000..911838864b --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/openssl/CryptoImpl.cpp @@ -0,0 +1,987 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <cstring> + +#include <aws/core/utils/memory/AWSMemory.h> +#include <aws/core/utils/crypto/openssl/CryptoImpl.h> +#include <aws/core/utils/Outcome.h> +#include <openssl/md5.h> + +#ifdef OPENSSL_IS_BORINGSSL +#ifdef _MSC_VER +AWS_SUPPRESS_WARNING_PUSH(4201) +#else +AWS_SUPPRESS_WARNING_PUSH("-Wpedantic") +#endif +#endif + +#include <openssl/sha.h> + +#ifdef OPENSSL_IS_BORINGSSL +AWS_SUPPRESS_WARNING_POP +#endif + +#include <openssl/err.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <thread> + +using namespace Aws::Utils; +using namespace Aws::Utils::Crypto; + +namespace Aws +{ + namespace Utils + { + namespace Crypto + { + namespace OpenSSL + { +/** + * openssl with OPENSSL_VERSION_NUMBER < 0x10100003L made data type details unavailable + * libressl use openssl with data type details available, but mandatorily set + * OPENSSL_VERSION_NUMBER = 0x20000000L, insane! + * https://github.com/aws/aws-sdk-cpp/pull/507/commits/2c99f1fe0c4b4683280caeb161538d4724d6a179 + */ +#if defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER == 0x20000000L) +#undef OPENSSL_VERSION_NUMBER +#define OPENSSL_VERSION_NUMBER 0x1000107fL +#endif +#define OPENSSL_VERSION_LESS_1_1 (OPENSSL_VERSION_NUMBER < 0x10100003L) + +#if OPENSSL_VERSION_LESS_1_1 + static const char* OPENSSL_INTERNALS_TAG = "OpenSSLCallbackState"; + static std::mutex* locks(nullptr); +#endif + + GetTheLights getTheLights; + + void init_static_state() + { +#if OPENSSL_VERSION_LESS_1_1 || defined(OPENSSL_IS_BORINGSSL) + ERR_load_crypto_strings(); +#else + OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS /*options*/ ,NULL /* OpenSSL init settings*/ ); +#endif +#if !defined(OPENSSL_IS_BORINGSSL) + OPENSSL_add_all_algorithms_noconf(); +#endif +#if OPENSSL_VERSION_LESS_1_1 + if (!CRYPTO_get_locking_callback()) + { + locks = Aws::NewArray<std::mutex>(static_cast<size_t>(CRYPTO_num_locks()), + OPENSSL_INTERNALS_TAG); + CRYPTO_set_locking_callback(&locking_fn); + } + + if (!CRYPTO_get_id_callback()) + { + CRYPTO_set_id_callback(&id_fn); + } +#endif + RAND_poll(); + } + + void cleanup_static_state() + { +#if OPENSSL_VERSION_LESS_1_1 + if (CRYPTO_get_locking_callback() == &locking_fn) + { + CRYPTO_set_locking_callback(nullptr); + assert(locks); + Aws::DeleteArray(locks); + locks = nullptr; + } + + if (CRYPTO_get_id_callback() == &id_fn) + { + CRYPTO_set_id_callback(nullptr); + } +#endif + } + +#if OPENSSL_VERSION_LESS_1_1 + void locking_fn(int mode, int n, const char*, int) + { + if (mode & CRYPTO_LOCK) + { + locks[n].lock(); + } + else + { + locks[n].unlock(); + } + } + + unsigned long id_fn() + { + return static_cast<unsigned long>(std::hash<std::thread::id>()(std::this_thread::get_id())); + } +#endif + } + + static const char* OPENSSL_LOG_TAG = "OpenSSLCipher"; + + void SecureRandomBytes_OpenSSLImpl::GetBytes(unsigned char* buffer, size_t bufferSize) + { + if (!bufferSize) + { + return; + } + + if (!buffer) + { + AWS_LOGSTREAM_FATAL(OPENSSL_LOG_TAG, "Secure Random Bytes generator can't generate: " << bufferSize << " bytes with nullptr buffer."); + assert(buffer); + return; + } + + int success = RAND_bytes(buffer, static_cast<int>(bufferSize)); + if (success != 1) + { + m_failure = true; + } + } + + class OpensslCtxRAIIGuard + { + public: + OpensslCtxRAIIGuard() + { + m_ctx = EVP_MD_CTX_create(); + assert(m_ctx != nullptr); + } + + ~OpensslCtxRAIIGuard() + { + EVP_MD_CTX_destroy(m_ctx); + m_ctx = nullptr; + } + + EVP_MD_CTX* getResource() + { + return m_ctx; + } + private: + EVP_MD_CTX *m_ctx; + }; + + HashResult MD5OpenSSLImpl::Calculate(const Aws::String& str) + { + OpensslCtxRAIIGuard guard; + auto ctx = guard.getResource(); +#if !defined(OPENSSL_IS_BORINGSSL) + EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); +#endif + EVP_DigestInit_ex(ctx, EVP_md5(), nullptr); + EVP_DigestUpdate(ctx, str.c_str(), str.size()); + + ByteBuffer hash(EVP_MD_size(EVP_md5())); + EVP_DigestFinal(ctx, hash.GetUnderlyingData(), nullptr); + + return HashResult(std::move(hash)); + } + + HashResult MD5OpenSSLImpl::Calculate(Aws::IStream& stream) + { + OpensslCtxRAIIGuard guard; + auto ctx = guard.getResource(); +#if !defined(OPENSSL_IS_BORINGSSL) + EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); +#endif + EVP_DigestInit_ex(ctx, EVP_md5(), nullptr); + + auto currentPos = stream.tellg(); + if (currentPos == -1) + { + currentPos = 0; + stream.clear(); + } + stream.seekg(0, stream.beg); + + char streamBuffer[Aws::Utils::Crypto::Hash::INTERNAL_HASH_STREAM_BUFFER_SIZE]; + while (stream.good()) + { + stream.read(streamBuffer, Aws::Utils::Crypto::Hash::INTERNAL_HASH_STREAM_BUFFER_SIZE); + auto bytesRead = stream.gcount(); + + if (bytesRead > 0) + { + EVP_DigestUpdate(ctx, streamBuffer, static_cast<size_t>(bytesRead)); + } + } + + stream.clear(); + stream.seekg(currentPos, stream.beg); + + ByteBuffer hash(EVP_MD_size(EVP_md5())); + EVP_DigestFinal(ctx, hash.GetUnderlyingData(), nullptr); + + return HashResult(std::move(hash)); + } + + HashResult Sha256OpenSSLImpl::Calculate(const Aws::String& str) + { + OpensslCtxRAIIGuard guard; + auto ctx = guard.getResource(); + EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr); + EVP_DigestUpdate(ctx, str.c_str(), str.size()); + + ByteBuffer hash(EVP_MD_size(EVP_sha256())); + EVP_DigestFinal(ctx, hash.GetUnderlyingData(), nullptr); + + return HashResult(std::move(hash)); + } + + HashResult Sha256OpenSSLImpl::Calculate(Aws::IStream& stream) + { + OpensslCtxRAIIGuard guard; + auto ctx = guard.getResource(); + + EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr); + + auto currentPos = stream.tellg(); + if (currentPos == -1) + { + currentPos = 0; + stream.clear(); + } + + stream.seekg(0, stream.beg); + + char streamBuffer[Aws::Utils::Crypto::Hash::INTERNAL_HASH_STREAM_BUFFER_SIZE]; + while (stream.good()) + { + stream.read(streamBuffer, Aws::Utils::Crypto::Hash::INTERNAL_HASH_STREAM_BUFFER_SIZE); + auto bytesRead = stream.gcount(); + + if (bytesRead > 0) + { + EVP_DigestUpdate(ctx, streamBuffer, static_cast<size_t>(bytesRead)); + } + } + + stream.clear(); + stream.seekg(currentPos, stream.beg); + + ByteBuffer hash(EVP_MD_size(EVP_sha256())); + EVP_DigestFinal(ctx, hash.GetUnderlyingData(), nullptr); + + return HashResult(std::move(hash)); + } + + class HMACRAIIGuard { + public: + HMACRAIIGuard() { +#if OPENSSL_VERSION_LESS_1_1 + m_ctx = Aws::New<HMAC_CTX>("AllocSha256HAMCOpenSSLContext"); +#else + m_ctx = HMAC_CTX_new(); +#endif + assert(m_ctx != nullptr); + } + + ~HMACRAIIGuard() { +#if OPENSSL_VERSION_LESS_1_1 + Aws::Delete<HMAC_CTX>(m_ctx); +#else + HMAC_CTX_free(m_ctx); +#endif + m_ctx = nullptr; + } + + HMAC_CTX* getResource() { + return m_ctx; + } + private: + HMAC_CTX *m_ctx; + }; + + HashResult Sha256HMACOpenSSLImpl::Calculate(const ByteBuffer& toSign, const ByteBuffer& secret) + { + unsigned int length = SHA256_DIGEST_LENGTH; + ByteBuffer digest(length); + memset(digest.GetUnderlyingData(), 0, length); + + HMACRAIIGuard guard; + HMAC_CTX* m_ctx = guard.getResource(); + +#if OPENSSL_VERSION_LESS_1_1 + HMAC_CTX_init(m_ctx); +#endif + + HMAC_Init_ex(m_ctx, secret.GetUnderlyingData(), static_cast<int>(secret.GetLength()), EVP_sha256(), + NULL); + HMAC_Update(m_ctx, toSign.GetUnderlyingData(), toSign.GetLength()); + HMAC_Final(m_ctx, digest.GetUnderlyingData(), &length); + +#if OPENSSL_VERSION_LESS_1_1 + HMAC_CTX_cleanup(m_ctx); +#else + HMAC_CTX_reset(m_ctx); +#endif + return HashResult(std::move(digest)); + } + + void LogErrors(const char* logTag = OPENSSL_LOG_TAG) + { + unsigned long errorCode = ERR_get_error(); + char errStr[256]; + ERR_error_string_n(errorCode, errStr, 256); + + AWS_LOGSTREAM_ERROR(logTag, errStr); + } + + OpenSSLCipher::OpenSSLCipher(const CryptoBuffer& key, size_t blockSizeBytes, bool ctrMode) : + SymmetricCipher(key, blockSizeBytes, ctrMode), m_encryptor_ctx(nullptr), m_decryptor_ctx(nullptr) + { + Init(); + } + + OpenSSLCipher::OpenSSLCipher(OpenSSLCipher&& toMove) : SymmetricCipher(std::move(toMove)), + m_encryptor_ctx(nullptr), m_decryptor_ctx(nullptr) + { + Init(); + EVP_CIPHER_CTX_copy(m_encryptor_ctx, toMove.m_encryptor_ctx); + EVP_CIPHER_CTX_copy(m_decryptor_ctx, toMove.m_decryptor_ctx); + EVP_CIPHER_CTX_cleanup(toMove.m_encryptor_ctx); + EVP_CIPHER_CTX_cleanup(toMove.m_decryptor_ctx); + } + + OpenSSLCipher::OpenSSLCipher(CryptoBuffer&& key, CryptoBuffer&& initializationVector, CryptoBuffer&& tag) : + SymmetricCipher(std::move(key), std::move(initializationVector), std::move(tag)), + m_encryptor_ctx(nullptr), m_decryptor_ctx(nullptr) + { + Init(); + } + + OpenSSLCipher::OpenSSLCipher(const CryptoBuffer& key, const CryptoBuffer& initializationVector, + const CryptoBuffer& tag) : + SymmetricCipher(key, initializationVector, tag), m_encryptor_ctx(nullptr), m_decryptor_ctx(nullptr) + { + Init(); + } + + OpenSSLCipher::~OpenSSLCipher() + { + Cleanup(); + if (m_encryptor_ctx) + { + EVP_CIPHER_CTX_free(m_encryptor_ctx); + m_encryptor_ctx = nullptr; + } + if (m_decryptor_ctx) + { + EVP_CIPHER_CTX_free(m_decryptor_ctx); + m_decryptor_ctx = nullptr; + } + } + + void OpenSSLCipher::Init() + { + if (m_failure) + { + return; + } + + if (!m_encryptor_ctx) + { + // EVP_CIPHER_CTX_init() will be called inside EVP_CIPHER_CTX_new(). + m_encryptor_ctx = EVP_CIPHER_CTX_new(); + assert(m_encryptor_ctx != nullptr); + } + else + { // _init is the same as _reset after openssl 1.1 + EVP_CIPHER_CTX_init(m_encryptor_ctx); + } + if (!m_decryptor_ctx) + { + // EVP_CIPHER_CTX_init() will be called inside EVP_CIPHER_CTX_new(). + m_decryptor_ctx = EVP_CIPHER_CTX_new(); + assert(m_decryptor_ctx != nullptr); + } + else + { // _init is the same as _reset after openssl 1.1 + EVP_CIPHER_CTX_init(m_decryptor_ctx); + } + m_emptyPlaintext = false; + } + + CryptoBuffer OpenSSLCipher::EncryptBuffer(const CryptoBuffer& unEncryptedData) + { + if (m_failure) + { + AWS_LOGSTREAM_FATAL(OPENSSL_LOG_TAG, "Cipher not properly initialized for encryption. Aborting"); + return CryptoBuffer(); + } + + int lengthWritten = static_cast<int>(unEncryptedData.GetLength() + (GetBlockSizeBytes() - 1)); + CryptoBuffer encryptedText(static_cast<size_t>( lengthWritten + (GetBlockSizeBytes() - 1))); + + if (!EVP_EncryptUpdate(m_encryptor_ctx, encryptedText.GetUnderlyingData(), &lengthWritten, + unEncryptedData.GetUnderlyingData(), + static_cast<int>(unEncryptedData.GetLength()))) + { + m_failure = true; + LogErrors(); + return CryptoBuffer(); + } + + if (static_cast<size_t>(lengthWritten) < encryptedText.GetLength()) + { + return CryptoBuffer(encryptedText.GetUnderlyingData(), static_cast<size_t>(lengthWritten)); + } + return encryptedText; + } + + CryptoBuffer OpenSSLCipher::FinalizeEncryption() + { + if (m_failure) + { + AWS_LOGSTREAM_FATAL(OPENSSL_LOG_TAG, "Cipher not properly initialized for encryption finalization. Aborting"); + return CryptoBuffer(); + } + + CryptoBuffer finalBlock(GetBlockSizeBytes()); + int writtenSize = 0; + if (!EVP_EncryptFinal_ex(m_encryptor_ctx, finalBlock.GetUnderlyingData(), &writtenSize)) + { + m_failure = true; + LogErrors(); + return CryptoBuffer(); + } + return CryptoBuffer(finalBlock.GetUnderlyingData(), static_cast<size_t>(writtenSize)); + } + + CryptoBuffer OpenSSLCipher::DecryptBuffer(const CryptoBuffer& encryptedData) + { + if (m_failure) + { + AWS_LOGSTREAM_FATAL(OPENSSL_LOG_TAG, "Cipher not properly initialized for decryption. Aborting"); + return CryptoBuffer(); + } + + int lengthWritten = static_cast<int>(encryptedData.GetLength() + (GetBlockSizeBytes() - 1)); + CryptoBuffer decryptedText(static_cast<size_t>(lengthWritten)); + + if (!EVP_DecryptUpdate(m_decryptor_ctx, decryptedText.GetUnderlyingData(), &lengthWritten, + encryptedData.GetUnderlyingData(), + static_cast<int>(encryptedData.GetLength()))) + { + m_failure = true; + LogErrors(); + return CryptoBuffer(); + } + + if (lengthWritten == 0) + { + m_emptyPlaintext = true; + } + if (static_cast<size_t>(lengthWritten) < decryptedText.GetLength()) + { + return CryptoBuffer(decryptedText.GetUnderlyingData(), static_cast<size_t>(lengthWritten)); + } + return decryptedText; + } + + CryptoBuffer OpenSSLCipher::FinalizeDecryption() + { + if (m_failure) + { + AWS_LOGSTREAM_FATAL(OPENSSL_LOG_TAG, "Cipher not properly initialized for decryption finalization. Aborting"); + return CryptoBuffer(); + } + + CryptoBuffer finalBlock(GetBlockSizeBytes()); + int writtenSize = static_cast<int>(finalBlock.GetLength()); + int ret = EVP_DecryptFinal_ex(m_decryptor_ctx, finalBlock.GetUnderlyingData(), &writtenSize); +#if OPENSSL_VERSION_NUMBER > 0x1010104fL //1.1.1d + if (ret <= 0) +#else + if (ret <= 0 && !m_emptyPlaintext) // see details why making exception for empty string at: https://github.com/aws/aws-sdk-cpp/issues/1413 +#endif + { + m_failure = true; + LogErrors(); + return CryptoBuffer(); + } + return CryptoBuffer(finalBlock.GetUnderlyingData(), static_cast<size_t>(writtenSize)); + } + + void OpenSSLCipher::Reset() + { + Cleanup(); + Init(); + } + + void OpenSSLCipher::Cleanup() + { + m_failure = false; + if (m_encryptor_ctx) EVP_CIPHER_CTX_cleanup(m_encryptor_ctx); + if (m_decryptor_ctx) EVP_CIPHER_CTX_cleanup(m_decryptor_ctx); + } + + bool OpenSSLCipher::CheckKeyAndIVLength(size_t expectedKeyLength, size_t expectedIVLength) + { + if (!m_failure && ((m_key.GetLength() != expectedKeyLength) || m_initializationVector.GetLength() != expectedIVLength)) + { + AWS_LOGSTREAM_ERROR(OPENSSL_LOG_TAG, "Expected Key size is: " << expectedKeyLength << " and expected IV size is: " << expectedIVLength); + m_failure = true; + } + return !m_failure; + } + + size_t AES_CBC_Cipher_OpenSSL::BlockSizeBytes = 16; + size_t AES_CBC_Cipher_OpenSSL::KeyLengthBits = 256; + static const char* CBC_LOG_TAG = "AES_CBC_Cipher_OpenSSL"; + + AES_CBC_Cipher_OpenSSL::AES_CBC_Cipher_OpenSSL(const CryptoBuffer& key) : OpenSSLCipher(key, BlockSizeBytes) + { + InitCipher(); + } + + AES_CBC_Cipher_OpenSSL::AES_CBC_Cipher_OpenSSL(CryptoBuffer&& key, CryptoBuffer&& initializationVector) : + OpenSSLCipher(std::move(key), std::move(initializationVector)) + { + InitCipher(); + } + + AES_CBC_Cipher_OpenSSL::AES_CBC_Cipher_OpenSSL(const CryptoBuffer& key, + const CryptoBuffer& initializationVector) : + OpenSSLCipher(key, initializationVector) + { + InitCipher(); + } + + void AES_CBC_Cipher_OpenSSL::InitCipher() + { + if (m_failure || !CheckKeyAndIVLength(KeyLengthBits/8, BlockSizeBytes)) + { + return; + } + + if (!EVP_EncryptInit_ex(m_encryptor_ctx, EVP_aes_256_cbc(), nullptr, m_key.GetUnderlyingData(), + m_initializationVector.GetUnderlyingData()) || + !EVP_DecryptInit_ex(m_decryptor_ctx, EVP_aes_256_cbc(), nullptr, m_key.GetUnderlyingData(), + m_initializationVector.GetUnderlyingData())) + { + m_failure = true; + LogErrors(CBC_LOG_TAG); + } + } + + size_t AES_CBC_Cipher_OpenSSL::GetBlockSizeBytes() const + { + return BlockSizeBytes; + } + + size_t AES_CBC_Cipher_OpenSSL::GetKeyLengthBits() const + { + return KeyLengthBits; + } + + void AES_CBC_Cipher_OpenSSL::Reset() + { + OpenSSLCipher::Reset(); + InitCipher(); + } + + size_t AES_CTR_Cipher_OpenSSL::BlockSizeBytes = 16; + size_t AES_CTR_Cipher_OpenSSL::KeyLengthBits = 256; + static const char* CTR_LOG_TAG = "AES_CTR_Cipher_OpenSSL"; + + AES_CTR_Cipher_OpenSSL::AES_CTR_Cipher_OpenSSL(const CryptoBuffer& key) : OpenSSLCipher(key, BlockSizeBytes, + true) + { + InitCipher(); + } + + AES_CTR_Cipher_OpenSSL::AES_CTR_Cipher_OpenSSL(CryptoBuffer&& key, CryptoBuffer&& initializationVector) : + OpenSSLCipher(std::move(key), std::move(initializationVector)) + { + InitCipher(); + } + + AES_CTR_Cipher_OpenSSL::AES_CTR_Cipher_OpenSSL(const CryptoBuffer& key, + const CryptoBuffer& initializationVector) : + OpenSSLCipher(key, initializationVector) + { + InitCipher(); + } + + void AES_CTR_Cipher_OpenSSL::InitCipher() + { + if (m_failure || !CheckKeyAndIVLength(KeyLengthBits/8, BlockSizeBytes)) + { + return; + } + + if (!(EVP_EncryptInit_ex(m_encryptor_ctx, EVP_aes_256_ctr(), nullptr, m_key.GetUnderlyingData(), + m_initializationVector.GetUnderlyingData()) + && EVP_CIPHER_CTX_set_padding(m_encryptor_ctx, 0)) || + !(EVP_DecryptInit_ex(m_decryptor_ctx, EVP_aes_256_ctr(), nullptr, m_key.GetUnderlyingData(), + m_initializationVector.GetUnderlyingData()) + && EVP_CIPHER_CTX_set_padding(m_decryptor_ctx, 0))) + { + m_failure = true; + LogErrors(CTR_LOG_TAG); + } + } + + size_t AES_CTR_Cipher_OpenSSL::GetBlockSizeBytes() const + { + return BlockSizeBytes; + } + + size_t AES_CTR_Cipher_OpenSSL::GetKeyLengthBits() const + { + return KeyLengthBits; + } + + void AES_CTR_Cipher_OpenSSL::Reset() + { + OpenSSLCipher::Reset(); + InitCipher(); + } + + size_t AES_GCM_Cipher_OpenSSL::BlockSizeBytes = 16; + size_t AES_GCM_Cipher_OpenSSL::KeyLengthBits = 256; + size_t AES_GCM_Cipher_OpenSSL::IVLengthBytes = 12; + size_t AES_GCM_Cipher_OpenSSL::TagLengthBytes = 16; + + static const char* GCM_LOG_TAG = "AES_GCM_Cipher_OpenSSL"; + + AES_GCM_Cipher_OpenSSL::AES_GCM_Cipher_OpenSSL(const CryptoBuffer& key) + : OpenSSLCipher(key, IVLengthBytes) + { + InitCipher(); + } + + AES_GCM_Cipher_OpenSSL::AES_GCM_Cipher_OpenSSL(const CryptoBuffer& key, const CryptoBuffer* aad) + : OpenSSLCipher(key, IVLengthBytes), m_aad(*aad) + { + InitCipher(); + } + + AES_GCM_Cipher_OpenSSL::AES_GCM_Cipher_OpenSSL(CryptoBuffer&& key, CryptoBuffer&& initializationVector, + CryptoBuffer&& tag, CryptoBuffer&& aad) : + OpenSSLCipher(std::move(key), std::move(initializationVector), std::move(tag)), m_aad(std::move(aad)) + { + InitCipher(); + } + + AES_GCM_Cipher_OpenSSL::AES_GCM_Cipher_OpenSSL(const CryptoBuffer& key, const CryptoBuffer& initializationVector, + const CryptoBuffer& tag, const CryptoBuffer& aad) : + OpenSSLCipher(key, initializationVector, tag), m_aad(std::move(aad)) + { + InitCipher(); + } + + CryptoBuffer AES_GCM_Cipher_OpenSSL::FinalizeEncryption() + { + if (m_failure) + { + AWS_LOGSTREAM_FATAL(GCM_LOG_TAG, "Cipher not properly initialized for encryption finalization. Aborting"); + return CryptoBuffer(); + } + + int writtenSize = 0; + CryptoBuffer finalBlock(GetBlockSizeBytes()); + EVP_EncryptFinal_ex(m_encryptor_ctx, finalBlock.GetUnderlyingData(), &writtenSize); + + m_tag = CryptoBuffer(TagLengthBytes); + if (!EVP_CIPHER_CTX_ctrl(m_encryptor_ctx, EVP_CTRL_GCM_GET_TAG, static_cast<int>(m_tag.GetLength()), + m_tag.GetUnderlyingData())) + { + m_failure = true; + LogErrors(GCM_LOG_TAG); + } + + return CryptoBuffer(); + } + + void AES_GCM_Cipher_OpenSSL::InitCipher() + { + if (m_failure || !CheckKeyAndIVLength(KeyLengthBits/8, IVLengthBytes)) + { + return; + } + + if (!(EVP_EncryptInit_ex(m_encryptor_ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr) && + EVP_EncryptInit_ex(m_encryptor_ctx, nullptr, nullptr, m_key.GetUnderlyingData(), + m_initializationVector.GetUnderlyingData()) && + EVP_CIPHER_CTX_set_padding(m_encryptor_ctx, 0)) || + !(EVP_DecryptInit_ex(m_decryptor_ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr) && + EVP_DecryptInit_ex(m_decryptor_ctx, nullptr, nullptr, m_key.GetUnderlyingData(), + m_initializationVector.GetUnderlyingData()) && + EVP_CIPHER_CTX_set_padding(m_decryptor_ctx, 0))) + { + m_failure = true; + LogErrors(GCM_LOG_TAG); + return; + } + + if (m_aad.GetLength() > 0) + { + int outLen = 0; + if(!EVP_EncryptUpdate(m_encryptor_ctx, nullptr, &outLen, m_aad.GetUnderlyingData(), m_aad.GetLength()) + || !EVP_DecryptUpdate(m_decryptor_ctx, nullptr, &outLen, m_aad.GetUnderlyingData(), m_aad.GetLength())) + { + m_failure = true; + LogErrors(GCM_LOG_TAG); + return; + } + } + + //tag should always be set in GCM decrypt mode + if (m_tag.GetLength() > 0) + { + if (m_tag.GetLength() < TagLengthBytes) + { + AWS_LOGSTREAM_ERROR(GCM_LOG_TAG, "Illegal attempt to decrypt an AES GCM payload without a valid tag set: tag length=" << m_tag.GetLength()); + m_failure = true; + return; + } + + if (!EVP_CIPHER_CTX_ctrl(m_decryptor_ctx, EVP_CTRL_GCM_SET_TAG, static_cast<int>(m_tag.GetLength()), m_tag.GetUnderlyingData())) + { + m_failure = true; + LogErrors(GCM_LOG_TAG); + } + } + } + + size_t AES_GCM_Cipher_OpenSSL::GetBlockSizeBytes() const + { + return BlockSizeBytes; + } + + size_t AES_GCM_Cipher_OpenSSL::GetKeyLengthBits() const + { + return KeyLengthBits; + } + + size_t AES_GCM_Cipher_OpenSSL::GetTagLengthBytes() const + { + return TagLengthBytes; + } + + void AES_GCM_Cipher_OpenSSL::Reset() + { + OpenSSLCipher::Reset(); + InitCipher(); + } + + size_t AES_KeyWrap_Cipher_OpenSSL::KeyLengthBits = 256; + size_t AES_KeyWrap_Cipher_OpenSSL::BlockSizeBytes = 8; + static const unsigned char INTEGRITY_VALUE = 0xA6; + static const size_t MIN_CEK_LENGTH_BYTES = 128 / 8; + + static const char* KEY_WRAP_TAG = "AES_KeyWrap_Cipher_OpenSSL"; + + AES_KeyWrap_Cipher_OpenSSL::AES_KeyWrap_Cipher_OpenSSL(const CryptoBuffer& key) : OpenSSLCipher(key, 0) + { + InitCipher(); + } + + CryptoBuffer AES_KeyWrap_Cipher_OpenSSL::EncryptBuffer(const CryptoBuffer& plainText) + { + if (!m_failure) + { + m_workingKeyBuffer = CryptoBuffer({&m_workingKeyBuffer, (CryptoBuffer*) &plainText}); + } + return CryptoBuffer(); + } + + CryptoBuffer AES_KeyWrap_Cipher_OpenSSL::FinalizeEncryption() + { + if (m_failure) + { + AWS_LOGSTREAM_FATAL(KEY_WRAP_TAG, "Cipher not properly initialized for encryption finalization. Aborting"); + return CryptoBuffer(); + } + + if (m_workingKeyBuffer.GetLength() < MIN_CEK_LENGTH_BYTES) + { + AWS_LOGSTREAM_ERROR(KEY_WRAP_TAG, "Incorrect input length of " << m_workingKeyBuffer.GetLength()); + m_failure = true; + return CryptoBuffer(); + } + + //the following is an in place implementation of + //RFC 3394 using the alternate in-place implementation. + //we use one in-place buffer instead of the copy at the end. + //the one letter variable names are meant to directly reflect the variables in the RFC + CryptoBuffer cipherText(m_workingKeyBuffer.GetLength() + BlockSizeBytes); + + //put the integrity check register in the first 8 bytes of the final buffer. + memset(cipherText.GetUnderlyingData(), INTEGRITY_VALUE, BlockSizeBytes); + unsigned char* a = cipherText.GetUnderlyingData(); + + //put the register buffer after the integrity check register + memcpy(cipherText.GetUnderlyingData() + BlockSizeBytes, m_workingKeyBuffer.GetUnderlyingData(), + m_workingKeyBuffer.GetLength()); + unsigned char* r = cipherText.GetUnderlyingData() + BlockSizeBytes; + + int n = static_cast<int>(m_workingKeyBuffer.GetLength() / BlockSizeBytes); + + //temporary encryption buffer + CryptoBuffer b(BlockSizeBytes * 2); + int outLen = static_cast<int>(b.GetLength()); + + //concatenation buffer + CryptoBuffer tempInput(BlockSizeBytes * 2); + + for (int j = 0; j <= 5; ++j) + { + for (int i = 1; i <= n; ++i) + { + //concat A and R[i], A should be most significant and then R[i] should be least significant. + memcpy(tempInput.GetUnderlyingData(), a, BlockSizeBytes); + memcpy(tempInput.GetUnderlyingData() + BlockSizeBytes, r, BlockSizeBytes); + + //encrypt the concatenated A and R[I] and store it in B + if (!EVP_EncryptUpdate(m_encryptor_ctx, b.GetUnderlyingData(), &outLen, + tempInput.GetUnderlyingData(), static_cast<int>(tempInput.GetLength()))) + { + LogErrors(KEY_WRAP_TAG); + m_failure = true; + return CryptoBuffer(); + } + + unsigned char t = static_cast<unsigned char>((n * j) + i); + //put the 64 MSB ^ T into A + memcpy(a, b.GetUnderlyingData(), BlockSizeBytes); + a[7] ^= t; + //put the 64 LSB into R[i] + memcpy(r, b.GetUnderlyingData() + BlockSizeBytes, BlockSizeBytes); + //increment i -> R[i] + r += BlockSizeBytes; + } + //reset R + r = cipherText.GetUnderlyingData() + BlockSizeBytes; + } + + return cipherText; + } + + CryptoBuffer AES_KeyWrap_Cipher_OpenSSL::DecryptBuffer(const CryptoBuffer& cipherText) + { + if (!m_failure) + { + m_workingKeyBuffer = CryptoBuffer({&m_workingKeyBuffer, (CryptoBuffer*)&cipherText}); + } + return CryptoBuffer(); + } + + CryptoBuffer AES_KeyWrap_Cipher_OpenSSL::FinalizeDecryption() + { + if (m_failure) + { + AWS_LOGSTREAM_FATAL(KEY_WRAP_TAG, "Cipher not properly initialized for decryption finalization. Aborting"); + return CryptoBuffer(); + } + + if (m_workingKeyBuffer.GetLength() < MIN_CEK_LENGTH_BYTES + BlockSizeBytes) + { + AWS_LOGSTREAM_ERROR(KEY_WRAP_TAG, "Incorrect input length of " << m_workingKeyBuffer.GetLength()); + m_failure = true; + return CryptoBuffer(); + } + + //the following is an in place implementation of + //RFC 3394 using the alternate in-place implementation. + //we use one in-place buffer instead of the copy at the end. + //the one letter variable names are meant to directly reflect the variables in the RFC + CryptoBuffer plainText(m_workingKeyBuffer.GetLength() - BlockSizeBytes); + memcpy(plainText.GetUnderlyingData(), m_workingKeyBuffer.GetUnderlyingData() + BlockSizeBytes, plainText.GetLength()); + + //integrity register should be the first 8 bytes of the cipher text + unsigned char* a = m_workingKeyBuffer.GetUnderlyingData(); + + //in-place register is the plaintext. For decryption, start at the last array position (8 bytes before the end); + unsigned char* r = plainText.GetUnderlyingData() + plainText.GetLength() - BlockSizeBytes; + + int n = static_cast<int>(plainText.GetLength() / BlockSizeBytes); + + //temporary encryption buffer + CryptoBuffer b(BlockSizeBytes * 10); + int outLen = static_cast<int>(b.GetLength()); + + //concatenation buffer + CryptoBuffer tempInput(BlockSizeBytes * 2); + + for(int j = 5; j >= 0; --j) + { + for(int i = n; i >= 1; --i) + { + //concat + //A ^ t + memcpy(tempInput.GetUnderlyingData(), a, BlockSizeBytes); + unsigned char t = static_cast<unsigned char>((n * j) + i); + tempInput[7] ^= t; + //R[i] + memcpy(tempInput.GetUnderlyingData() + BlockSizeBytes, r, BlockSizeBytes); + + //Decrypt the concatenated buffer + if(!EVP_DecryptUpdate(m_decryptor_ctx, b.GetUnderlyingData(), &outLen, + tempInput.GetUnderlyingData(), static_cast<int>(tempInput.GetLength()))) + { + m_failure = true; + LogErrors(KEY_WRAP_TAG); + return CryptoBuffer(); + } + + //set A to MSB 64 bits of decrypted result + memcpy(a, b.GetUnderlyingData(), BlockSizeBytes); + //set R[i] to LSB 64 bits of decrypted result + memcpy(r, b.GetUnderlyingData() + BlockSizeBytes, BlockSizeBytes); + //decrement i -> R[i] + r -= BlockSizeBytes; + } + + r = plainText.GetUnderlyingData() + plainText.GetLength() - BlockSizeBytes; + } + + //here we perform the integrity check to make sure A == 0xA6A6A6A6A6A6A6A6 + for(size_t i = 0; i < BlockSizeBytes; ++i) + { + if(a[i] != INTEGRITY_VALUE) + { + m_failure = true; + AWS_LOGSTREAM_ERROR(KEY_WRAP_TAG, "Integrity check failed for key wrap decryption."); + return CryptoBuffer(); + } + } + + return plainText; + } + + void AES_KeyWrap_Cipher_OpenSSL::InitCipher() + { + if (m_failure || !CheckKeyAndIVLength(KeyLengthBits/8, 0)) + { + return; + } + + if (!(EVP_EncryptInit_ex(m_encryptor_ctx, EVP_aes_256_ecb(), nullptr, m_key.GetUnderlyingData(), nullptr) && + EVP_CIPHER_CTX_set_padding(m_encryptor_ctx, 0)) || + !(EVP_DecryptInit_ex(m_decryptor_ctx, EVP_aes_256_ecb(), nullptr, m_key.GetUnderlyingData(), nullptr) && + EVP_CIPHER_CTX_set_padding(m_decryptor_ctx, 0))) + { + m_failure = true; + LogErrors(KEY_WRAP_TAG); + } + } + + void AES_KeyWrap_Cipher_OpenSSL::Reset() + { + m_workingKeyBuffer = CryptoBuffer(); + OpenSSLCipher::Reset(); + InitCipher(); + } + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventDecoderStream.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventDecoderStream.cpp new file mode 100644 index 0000000000..5ecd2d0444 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventDecoderStream.cpp @@ -0,0 +1,22 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include <aws/core/utils/event/EventDecoderStream.h> +#include <iostream> + +namespace Aws +{ + namespace Utils + { + namespace Event + { + EventDecoderStream::EventDecoderStream(EventStreamDecoder& decoder, size_t bufferSize) : + Aws::IOStream(&m_eventStreamBuf), + m_eventStreamBuf(decoder, bufferSize) + + { + } + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventEncoderStream.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventEncoderStream.cpp new file mode 100644 index 0000000000..f8640f0e8c --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventEncoderStream.cpp @@ -0,0 +1,28 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include <aws/core/utils/event/EventEncoderStream.h> +#include <iostream> + +namespace Aws +{ + namespace Utils + { + namespace Event + { + EventEncoderStream::EventEncoderStream(size_t bufferSize) : + Aws::IOStream(&m_streambuf), + m_streambuf(bufferSize) + { + } + + EventEncoderStream& EventEncoderStream::WriteEvent(const Aws::Utils::Event::Message& msg) + { + auto bits = m_encoder.EncodeAndSign(msg); + write(reinterpret_cast<char*>(bits.data()), bits.size()); + return *this; + } + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventHeader.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventHeader.cpp new file mode 100644 index 0000000000..c3c989bedb --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventHeader.cpp @@ -0,0 +1,107 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/event/EventHeader.h> +#include <aws/core/utils/HashingUtils.h> + +namespace Aws +{ + namespace Utils + { + namespace Event + { + static const int HASH_BOOL_TRUE = HashingUtils::HashString("BOOL_TRUE"); + static const int HASH_BOOL_FALSE = HashingUtils::HashString("BOOL_FALSE"); + static const int HASH_BYTE = HashingUtils::HashString("BYTE"); + static const int HASH_INT16 = HashingUtils::HashString("INT16"); + static const int HASH_INT32 = HashingUtils::HashString("INT32"); + static const int HASH_INT64 = HashingUtils::HashString("INT64"); + static const int HASH_BYTE_BUF = HashingUtils::HashString("BYTE_BUFFER"); + static const int HASH_STRING = HashingUtils::HashString("STRING"); + static const int HASH_TIMESTAMP = HashingUtils::HashString("TIMESTAMP"); + static const int HASH_UUID = HashingUtils::HashString("UUID"); + + EventHeaderValue::EventHeaderType EventHeaderValue::GetEventHeaderTypeForName(const Aws::String& name) + { + int hashCode = Aws::Utils::HashingUtils::HashString(name.c_str()); + if (hashCode == HASH_BOOL_TRUE) + { + return EventHeaderType::BOOL_TRUE; + } + else if (hashCode == HASH_BOOL_FALSE) + { + return EventHeaderType::BOOL_FALSE; + } + else if (hashCode == HASH_BYTE) + { + return EventHeaderType::BYTE; + } + else if (hashCode == HASH_INT16) + { + return EventHeaderType::INT16; + } + else if (hashCode == HASH_INT32) + { + return EventHeaderType::INT32; + } + else if (hashCode == HASH_INT64) + { + return EventHeaderType::INT64; + } + else if (hashCode == HASH_BYTE_BUF) + { + return EventHeaderType::BYTE_BUF; + } + else if (hashCode == HASH_STRING) + { + return EventHeaderType::STRING; + } + else if (hashCode == HASH_TIMESTAMP) + { + return EventHeaderType::TIMESTAMP; + } + else if (hashCode == HASH_UUID) + { + return EventHeaderType::UUID; + } + else + { + return EventHeaderType::UNKNOWN; + } + } + + Aws::String EventHeaderValue::GetNameForEventHeaderType(EventHeaderType value) + { + switch (value) + { + case EventHeaderType::BOOL_TRUE: + return "BOOL_TRUE"; + case EventHeaderType::BOOL_FALSE: + return "BOOL_FALSE"; + case EventHeaderType::BYTE: + return "BYTE"; + case EventHeaderType::INT16: + return "INT16"; + case EventHeaderType::INT32: + return "INT32"; + case EventHeaderType::INT64: + return "INT64"; + case EventHeaderType::BYTE_BUF: + return "BYTE_BUF"; + case EventHeaderType::STRING: + return "STRING"; + case EventHeaderType::TIMESTAMP: + return "TIMESTAMP"; + case EventHeaderType::UUID: + return "UUID"; + default: + return "UNKNOWN"; + } + } + + } + } +} + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventMessage.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventMessage.cpp new file mode 100644 index 0000000000..de8b904775 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventMessage.cpp @@ -0,0 +1,132 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/event/EventMessage.h> +#include <aws/core/utils/HashingUtils.h> +#include <algorithm> +#include <iterator> + +namespace Aws +{ + namespace Utils + { + namespace Event + { + const char EVENT_TYPE_HEADER[] = ":event-type"; + const char CONTENT_TYPE_HEADER[] = ":content-type"; + const char MESSAGE_TYPE_HEADER[] = ":message-type"; + const char ERROR_CODE_HEADER[] = ":error-code"; + const char ERROR_MESSAGE_HEADER[] = ":error-message"; + const char EXCEPTION_TYPE_HEADER[] = ":exception-type"; + + static const int EVENT_HASH = HashingUtils::HashString("event"); + static const int ERROR_HASH = HashingUtils::HashString("error"); + static const int EXCEPTION_HASH = HashingUtils::HashString("exception"); + + static const int CONTENT_TYPE_APPLICATION_OCTET_STREAM_HASH = HashingUtils::HashString("application/octet-stream"); + static const int CONTENT_TYPE_APPLICATION_JSON_HASH = HashingUtils::HashString("application/json"); + static const int CONTENT_TYPE_TEXT_PLAIN_HASH = HashingUtils::HashString("text/plain"); + + Message::MessageType Message::GetMessageTypeForName(const Aws::String& name) + { + int hashCode = Aws::Utils::HashingUtils::HashString(name.c_str()); + if (hashCode == EVENT_HASH) + { + return MessageType::EVENT; + } + else if (hashCode == ERROR_HASH) + { + return MessageType::REQUEST_LEVEL_ERROR; + } + else if (hashCode == EXCEPTION_HASH) + { + return MessageType::REQUEST_LEVEL_EXCEPTION; + } + else + { + return MessageType::UNKNOWN; + } + } + + Aws::String Message::GetNameForMessageType(MessageType value) + { + switch (value) + { + case MessageType::EVENT: + return "event"; + case MessageType::REQUEST_LEVEL_ERROR: + return "error"; + case MessageType::REQUEST_LEVEL_EXCEPTION: + return "exception"; + default: + return "unknown"; + } + } + + Message::ContentType Message::GetContentTypeForName(const Aws::String& name) + { + int hashCode = Aws::Utils::HashingUtils::HashString(name.c_str()); + if (hashCode == CONTENT_TYPE_APPLICATION_OCTET_STREAM_HASH) + { + return ContentType::APPLICATION_OCTET_STREAM; + } + else if (hashCode == CONTENT_TYPE_APPLICATION_JSON_HASH) + { + return ContentType::APPLICATION_JSON; + } + else if (hashCode == CONTENT_TYPE_TEXT_PLAIN_HASH) + { + return ContentType::TEXT_PLAIN; + } + else + { + return ContentType::UNKNOWN; + } + } + + Aws::String Message::GetNameForContentType(ContentType value) + { + switch (value) + { + case ContentType::APPLICATION_OCTET_STREAM: + return "application/octet-stream"; + case ContentType::APPLICATION_JSON: + return "application/json"; + case ContentType::TEXT_PLAIN: + return "text/plain"; + default: + return "unknown"; + } + } + + void Message::Reset() + { + m_totalLength = 0; + m_headersLength = 0; + m_payloadLength = 0; + + m_eventHeaders.clear(); + m_eventPayload.clear(); + } + + void Message::WriteEventPayload(const unsigned char* data, size_t length) + { + std::copy(data, data + length, std::back_inserter(m_eventPayload)); + } + + void Message::WriteEventPayload(const Aws::Vector<unsigned char>& bits) + { + std::copy(bits.cbegin(), bits.cend(), std::back_inserter(m_eventPayload)); + } + + void Message::WriteEventPayload(const Aws::String& bits) + { + std::copy(bits.cbegin(), bits.cend(), std::back_inserter(m_eventPayload)); + } + + } // namespace Event + } // namespace Utils +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamBuf.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamBuf.cpp new file mode 100644 index 0000000000..6a1766bb9f --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamBuf.cpp @@ -0,0 +1,147 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include <aws/core/utils/event/EventStreamBuf.h> +#include <cassert> + +namespace Aws +{ + namespace Utils + { + namespace Event + { + const size_t DEFAULT_BUF_SIZE = 1024; + + EventStreamBuf::EventStreamBuf(EventStreamDecoder& decoder, size_t bufferLength) : + m_byteBuffer(bufferLength), + m_bufferLength(bufferLength), + m_decoder(decoder) + { + assert(decoder); + char* begin = reinterpret_cast<char*>(m_byteBuffer.GetUnderlyingData()); + char* end = begin + bufferLength - 1; + + setp(begin, end); + setg(begin, begin, begin); + } + + EventStreamBuf::~EventStreamBuf() + { + if (m_decoder) + { + writeToDecoder(); + } + } + + void EventStreamBuf::writeToDecoder() + { + if (pptr() > pbase()) + { + size_t length = static_cast<size_t>(pptr() - pbase()); + m_decoder.Pump(m_byteBuffer, length); + + if (!m_decoder) + { + m_err.write(reinterpret_cast<char*>(m_byteBuffer.GetUnderlyingData()), length); + } + else + { + pbump(-static_cast<int>(length)); + } + } + } + + std::streampos EventStreamBuf::seekoff(std::streamoff off, std::ios_base::seekdir dir, std::ios_base::openmode which) + { + if (dir == std::ios_base::beg) + { + return seekpos(off, which); + } + else if (dir == std::ios_base::end) + { + return seekpos(m_bufferLength - 1 - off, which); + } + else if (dir == std::ios_base::cur) + { + if (which == std::ios_base::in) + { + return seekpos((gptr() - (char*)m_byteBuffer.GetUnderlyingData()) + off, which); + } + if (which == std::ios_base::out) + { + return seekpos((pptr() - (char*)m_byteBuffer.GetUnderlyingData()) + off, which); + } + } + + return std::streamoff(-1); + } + + std::streampos EventStreamBuf::seekpos(std::streampos pos, std::ios_base::openmode which) + { + assert(static_cast<size_t>(pos) <= m_bufferLength); + if (static_cast<size_t>(pos) > m_bufferLength) + { + return std::streampos(std::streamoff(-1)); + } + + if (which == std::ios_base::in) + { + m_err.seekg(pos); + return m_err.tellg(); + } + + if (which == std::ios_base::out) + { + return pos; + } + + return std::streampos(std::streamoff(-1)); + } + + int EventStreamBuf::underflow() + { + if (!m_err || m_err.eof() || m_decoder) + { + return std::char_traits<char>::eof(); + } + + m_err.flush(); + m_err.read(reinterpret_cast<char*>(m_byteBuffer.GetUnderlyingData()), m_byteBuffer.GetLength()); + + char* begin = reinterpret_cast<char*>(m_byteBuffer.GetUnderlyingData()); + setg(begin, begin, begin + m_err.gcount()); + return std::char_traits<char>::to_int_type(*gptr()); + } + + int EventStreamBuf::overflow(int ch) + { + auto eof = std::char_traits<char>::eof(); + + if (m_decoder) + { + if (ch != eof) + { + *pptr() = (char)ch; + pbump(1); + } + + writeToDecoder(); + return ch; + } + + return eof; + } + + int EventStreamBuf::sync() + { + if (m_decoder) + { + writeToDecoder(); + } + + return 0; + } + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamDecoder.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamDecoder.cpp new file mode 100644 index 0000000000..f70a6c88f6 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamDecoder.cpp @@ -0,0 +1,170 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/common/common.h> +#include <aws/core/utils/event/EventHeader.h> +#include <aws/core/utils/event/EventMessage.h> +#include <aws/core/utils/event/EventStreamDecoder.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/UnreferencedParam.h> +#include <aws/core/utils/memory/AWSMemory.h> + +namespace Aws +{ + namespace Utils + { + namespace Event + { + static const char EVENT_STREAM_DECODER_CLASS_TAG[] = "Aws::Utils::Event::EventStreamDecoder"; + + EventStreamDecoder::EventStreamDecoder(EventStreamHandler* handler) : m_eventStreamHandler(handler) + { + aws_event_stream_streaming_decoder_init(&m_decoder, + get_aws_allocator(), + onPayloadSegment, + onPreludeReceived, + onHeaderReceived, + onError, + (void*)handler); + } + + EventStreamDecoder::~EventStreamDecoder() + { + aws_event_stream_streaming_decoder_clean_up(&m_decoder); + } + + void EventStreamDecoder::Pump(const ByteBuffer& data) + { + Pump(data, data.GetLength()); + } + + void EventStreamDecoder::Pump(const ByteBuffer& data, size_t length) + { + aws_byte_buf dataBuf = aws_byte_buf_from_array(static_cast<uint8_t*>(data.GetUnderlyingData()), length); + aws_event_stream_streaming_decoder_pump(&m_decoder, &dataBuf); + } + + void EventStreamDecoder::Reset() + { + m_eventStreamHandler->Reset(); + } + + void EventStreamDecoder::ResetEventStreamHandler(EventStreamHandler* handler) + { + aws_event_stream_streaming_decoder_init(&m_decoder, get_aws_allocator(), + onPayloadSegment, + onPreludeReceived, + onHeaderReceived, + onError, + reinterpret_cast<void *>(handler)); + } + + void EventStreamDecoder::onPayloadSegment( + aws_event_stream_streaming_decoder* decoder, + aws_byte_buf* payload, + int8_t isFinalSegment, + void* context) + { + AWS_UNREFERENCED_PARAM(decoder); + auto handler = static_cast<EventStreamHandler*>(context); + assert(handler); + if (!handler) + { + AWS_LOGSTREAM_ERROR(EVENT_STREAM_DECODER_CLASS_TAG, "Payload received, but decoder encountered internal errors before." + "ErrorCode: " << EventStreamErrorsMapper::GetNameForError(handler->GetInternalError()) << ", " + "ErrorMessage: " << handler->GetEventPayloadAsString()); + return; + } + handler->WriteMessageEventPayload(static_cast<unsigned char*>(payload->buffer), payload->len); + + // Complete payload received + if (isFinalSegment == 1) + { + assert(handler->IsMessageCompleted()); + handler->OnEvent(); + handler->Reset(); + } + } + + void EventStreamDecoder::onPreludeReceived( + aws_event_stream_streaming_decoder* decoder, + aws_event_stream_message_prelude* prelude, + void* context) + { + AWS_UNREFERENCED_PARAM(decoder); + auto handler = static_cast<EventStreamHandler*>(context); + handler->Reset(); + + //Encounter internal error in prelude received. + //This error will be handled by OnError callback function later. + if (prelude->total_len < prelude->headers_len + 16) + { + return; + } + handler->SetMessageMetadata(prelude->total_len, prelude->headers_len, + prelude->total_len - prelude->headers_len - 4/*total byte-length*/ - 4/*headers byte-length*/ - 4/*prelude crc*/ - 4/*message crc*/); + AWS_LOGSTREAM_TRACE(EVENT_STREAM_DECODER_CLASS_TAG, "Message received, the expected length of the message is: " << prelude->total_len << + " bytes, and the expected length of the header is: " << prelude->headers_len << " bytes"); + + //Handle empty message + //if (handler->m_message.GetHeadersLength() == 0 && handler->m_message.GetPayloadLength() == 0) + if (handler->IsMessageCompleted()) + { + handler->OnEvent(); + handler->Reset(); + } + } + + void EventStreamDecoder::onHeaderReceived( + aws_event_stream_streaming_decoder* decoder, + aws_event_stream_message_prelude* prelude, + aws_event_stream_header_value_pair* header, + void* context) + { + AWS_UNREFERENCED_PARAM(decoder); + AWS_UNREFERENCED_PARAM(prelude); + auto handler = static_cast<EventStreamHandler*>(context); + assert(handler); + if (!handler) + { + AWS_LOGSTREAM_ERROR(EVENT_STREAM_DECODER_CLASS_TAG, "Payload received, but decoder encountered internal errors before." + "ErrorCode: " << EventStreamErrorsMapper::GetNameForError(handler->GetInternalError()) << ", " + "ErrorMessage: " << handler->GetEventPayloadAsString()); + return; + } + + // The length of a header = 1 byte (to represent the length of header name) + length of header name + 1 byte (to represent header type) + // + 2 bytes (to represent length of header value) + length of header value + handler->InsertMessageEventHeader(Aws::String(header->header_name, header->header_name_len), + 1 + header->header_name_len + 1 + 2 + header->header_value_len, EventHeaderValue(header)); + + // Handle messages only have headers, but without payload. + //if (handler->m_message.GetHeadersLength() == handler->m_headersBytesReceived() && handler->m_message.GetPayloadLength() == 0) + if (handler->IsMessageCompleted()) + { + handler->OnEvent(); + handler->Reset(); + } + } + + void EventStreamDecoder::onError( + aws_event_stream_streaming_decoder* decoder, + aws_event_stream_message_prelude* prelude, + int error_code, + const char* message, + void* context) + { + AWS_UNREFERENCED_PARAM(decoder); + AWS_UNREFERENCED_PARAM(prelude); + auto handler = static_cast<EventStreamHandler*>(context); + handler->SetFailure(); + handler->SetInternalError(error_code); + handler->WriteMessageEventPayload(reinterpret_cast<const unsigned char*>(message), strlen(message)); + handler->OnEvent(); + } + } // namespace Event + } // namespace Utils +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamEncoder.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamEncoder.cpp new file mode 100644 index 0000000000..ef7104e839 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamEncoder.cpp @@ -0,0 +1,162 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/event/EventHeader.h> +#include <aws/core/utils/event/EventMessage.h> +#include <aws/core/utils/event/EventStreamEncoder.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/auth/AWSAuthSigner.h> +#include <aws/common/byte_order.h> +#include <aws/core/utils/memory/AWSMemory.h> + +#include <cassert> + +namespace Aws +{ + namespace Utils + { + namespace Event + { + static const char TAG[] = "EventStreamEncoder"; + + static void EncodeHeaders(const Aws::Utils::Event::Message& msg, aws_array_list* headers) + { + aws_array_list_init_dynamic(headers, get_aws_allocator(), msg.GetEventHeaders().size(), sizeof(aws_event_stream_header_value_pair)); + for (auto&& header : msg.GetEventHeaders()) + { + const uint8_t headerKeyLen = static_cast<uint8_t>(header.first.length()); + switch(header.second.GetType()) + { + case EventHeaderValue::EventHeaderType::BOOL_TRUE: + case EventHeaderValue::EventHeaderType::BOOL_FALSE: + aws_event_stream_add_bool_header(headers, header.first.c_str(), headerKeyLen, header.second.GetEventHeaderValueAsBoolean()); + break; + case EventHeaderValue::EventHeaderType::BYTE: + aws_event_stream_add_bool_header(headers, header.first.c_str(), headerKeyLen, header.second.GetEventHeaderValueAsByte()); + break; + case EventHeaderValue::EventHeaderType::INT16: + aws_event_stream_add_int16_header(headers, header.first.c_str(), headerKeyLen, header.second.GetEventHeaderValueAsInt16()); + break; + case EventHeaderValue::EventHeaderType::INT32: + aws_event_stream_add_int32_header(headers, header.first.c_str(), headerKeyLen, header.second.GetEventHeaderValueAsInt32()); + break; + case EventHeaderValue::EventHeaderType::INT64: + aws_event_stream_add_int64_header(headers, header.first.c_str(), headerKeyLen, header.second.GetEventHeaderValueAsInt64()); + break; + case EventHeaderValue::EventHeaderType::BYTE_BUF: + { + const auto& bytes = header.second.GetEventHeaderValueAsBytebuf(); + aws_event_stream_add_bytebuf_header(headers, header.first.c_str(), headerKeyLen, bytes.GetUnderlyingData(), static_cast<uint16_t>(bytes.GetLength()), 1 /*copy*/); + } + break; + case EventHeaderValue::EventHeaderType::STRING: + { + const auto& bytes = header.second.GetUnderlyingBuffer(); + aws_event_stream_add_string_header(headers, header.first.c_str(), headerKeyLen, reinterpret_cast<char*>(bytes.GetUnderlyingData()), static_cast<uint16_t>(bytes.GetLength()), 0 /*copy*/); + } + break; + case EventHeaderValue::EventHeaderType::TIMESTAMP: + aws_event_stream_add_timestamp_header(headers, header.first.c_str(), headerKeyLen, header.second.GetEventHeaderValueAsTimestamp()); + break; + case EventHeaderValue::EventHeaderType::UUID: + { + ByteBuffer uuidBytes = header.second.GetEventHeaderValueAsUuid(); + aws_event_stream_add_uuid_header(headers, header.first.c_str(), headerKeyLen, uuidBytes.GetUnderlyingData()); + } + break; + default: + AWS_LOG_ERROR(TAG, "Encountered unknown type of header."); + break; + } + } + } + + EventStreamEncoder::EventStreamEncoder(Client::AWSAuthSigner* signer) : m_signer(signer) + { + } + + + Aws::Vector<unsigned char> EventStreamEncoder::EncodeAndSign(const Aws::Utils::Event::Message& msg) + { + aws_event_stream_message encoded = Encode(msg); + aws_event_stream_message signedMessage = Sign(&encoded); + + const auto signedMessageLength = signedMessage.message_buffer ? aws_event_stream_message_total_length(&signedMessage) : 0; + + Aws::Vector<unsigned char> outputBits(signedMessage.message_buffer, signedMessage.message_buffer + signedMessageLength); + aws_event_stream_message_clean_up(&encoded); + aws_event_stream_message_clean_up(&signedMessage); + return outputBits; + } + + aws_event_stream_message EventStreamEncoder::Encode(const Aws::Utils::Event::Message& msg) + { + aws_array_list headers; + EncodeHeaders(msg, &headers); + + aws_byte_buf payload; + payload.len = msg.GetEventPayload().size(); + // this const_cast is OK because aws_byte_buf will only be "read from" by the following functions. + payload.buffer = const_cast<uint8_t*>(msg.GetEventPayload().data()); + payload.capacity = 0; + payload.allocator = nullptr; + + aws_event_stream_message encoded; + if(aws_event_stream_message_init(&encoded, get_aws_allocator(), &headers, &payload) == AWS_OP_ERR) + { + AWS_LOGSTREAM_ERROR(TAG, "Error creating event-stream message from payload."); + aws_event_stream_headers_list_cleanup(&headers); + // GCC 4.9.4 issues a warning with -Wextra if we simply do + // return {}; + aws_event_stream_message empty{nullptr, nullptr, 0}; + return empty; + } + aws_event_stream_headers_list_cleanup(&headers); + return encoded; + } + + aws_event_stream_message EventStreamEncoder::Sign(aws_event_stream_message* msg) + { + const auto msglen = msg->message_buffer ? aws_event_stream_message_total_length(msg) : 0; + Event::Message signedMessage; + signedMessage.WriteEventPayload(msg->message_buffer, msglen); + + assert(m_signer); + if (!m_signer->SignEventMessage(signedMessage, m_signatureSeed)) + { + AWS_LOGSTREAM_ERROR(TAG, "Failed to sign event message frame."); + // GCC 4.9.4 issues a warning with -Wextra if we simply do + // return {}; + aws_event_stream_message empty{nullptr, nullptr, 0}; + return empty; + } + + aws_array_list headers; + EncodeHeaders(signedMessage, &headers); + + aws_byte_buf payload; + payload.len = signedMessage.GetEventPayload().size(); + payload.buffer = signedMessage.GetEventPayload().data(); + payload.capacity = 0; + payload.allocator = nullptr; + + aws_event_stream_message signedmsg; + if(aws_event_stream_message_init(&signedmsg, get_aws_allocator(), &headers, &payload)) + { + AWS_LOGSTREAM_ERROR(TAG, "Error creating event-stream message from payload."); + aws_event_stream_headers_list_cleanup(&headers); + // GCC 4.9.4 issues a warning with -Wextra if we simply do + // return {}; + aws_event_stream_message empty{nullptr, nullptr, 0}; + return empty; + } + aws_event_stream_headers_list_cleanup(&headers); + return signedmsg; + } + + } // namespace Event + } // namespace Utils +} // namespace Aws + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamErrors.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamErrors.cpp new file mode 100644 index 0000000000..836d0b47c5 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamErrors.cpp @@ -0,0 +1,66 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include <aws/core/client/AWSError.h> +#include <aws/core/utils/HashingUtils.h> +#include <aws/core/utils/event/EventStreamErrors.h> + + using namespace Aws::Client; +// using namespace Aws::S3; +// using namespace Aws::Utils; + +namespace Aws +{ + namespace Utils + { + namespace Event + { + namespace EventStreamErrorsMapper + { + /* + static const int EVENT_STREAM_NO_ERROR_HASH = HashingUtils::HashString("EventStreamNoError"); + static const int EVENT_STREAM_BUFFER_LENGTH_MISMATCH_HASH = HashingUtils::HashString("EventStreamBufferLengthMismatch"); + static const int EVENT_STREAM_INSUFFICIENT_BUFFER_LEN_HASH = HashingUtils::HashString("EventStreamInsufficientBufferLen"); + static const int EVENT_STREAM_MESSAGE_FIELD_SIZE_EXCEEDED_HASH = HashingUtils::HashString("EventStreamMessageFieldSizeExceeded"); + static const int EVENT_STREAM_PRELUDE_CHECKSUM_FAILURE_HASH = HashingUtils::HashString("EventStreamPreludeChecksumFailure"); + static const int EVENT_STREAM_MESSAGE_CHECKSUM_FAILURE_HASH = HashingUtils::HashString("EventStreamMessageChecksumFailure"); + static const int EVENT_STREAM_MESSAGE_INVALID_HEADERS_LEN_HASH = HashingUtils::HashString("EventStreamMessageInvalidHeadersLen"); + static const int EVENT_STREAM_MESSAGE_UNKNOWN_HEADER_TYPE_HASH = HashingUtils::HashString("EventStreamMessageUnknownHeaderType"); + static const int EVENT_STREAM_MESSAGE_PARSER_ILLEGAL_STATE_HASH = HashingUtils::HashString("EventStreamMessageParserIllegalState"); + */ + const char* GetNameForError(EventStreamErrors error) + { + switch (error) + { + case EventStreamErrors::EVENT_STREAM_NO_ERROR: + return "EventStreamNoError"; + case EventStreamErrors::EVENT_STREAM_BUFFER_LENGTH_MISMATCH: + return "EventStreamBufferLengthMismatch"; + case EventStreamErrors::EVENT_STREAM_INSUFFICIENT_BUFFER_LEN: + return "EventStreamInsufficientBufferLen"; + case EventStreamErrors::EVENT_STREAM_MESSAGE_FIELD_SIZE_EXCEEDED: + return "EventStreamMessageFieldSizeExceeded"; + case EventStreamErrors::EVENT_STREAM_PRELUDE_CHECKSUM_FAILURE: + return "EventStreamPreludeChecksumFailure"; + case EventStreamErrors::EVENT_STREAM_MESSAGE_CHECKSUM_FAILURE: + return "EventStreamMessageChecksumFailure"; + case EventStreamErrors::EVENT_STREAM_MESSAGE_INVALID_HEADERS_LEN: + return "EventStreamMessageInvalidHeadersLen"; + case EventStreamErrors::EVENT_STREAM_MESSAGE_UNKNOWN_HEADER_TYPE: + return "EventStreamMessageUnknownHeaderType"; + case EventStreamErrors::EVENT_STREAM_MESSAGE_PARSER_ILLEGAL_STATE: + return "EventStreamMessageParserIllegalState"; + default: + return "EventStreamUnknownError"; + } + } + + AWSError<CoreErrors> GetAwsErrorForEventStreamError(EventStreamErrors error) + { + return AWSError<CoreErrors>(CoreErrors::UNKNOWN, GetNameForError(error), "", false); + } + } // namespace EventStreamErrorsMapper + } // namespace Event + } // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/json/JsonSerializer.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/json/JsonSerializer.cpp new file mode 100644 index 0000000000..9b785d1995 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/json/JsonSerializer.cpp @@ -0,0 +1,665 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/json/JsonSerializer.h> + +#include <iterator> +#include <algorithm> +#include <aws/core/utils/memory/stl/AWSStringStream.h> +#include <aws/core/utils/StringUtils.h> + +using namespace Aws::Utils; +using namespace Aws::Utils::Json; + +JsonValue::JsonValue() : m_wasParseSuccessful(true) +{ + m_value = nullptr; +} + +JsonValue::JsonValue(cJSON* value) : + m_value(cJSON_Duplicate(value, true /* recurse */)), + m_wasParseSuccessful(true) +{ +} + +JsonValue::JsonValue(const Aws::String& value) : m_wasParseSuccessful(true) +{ + const char* return_parse_end; + m_value = cJSON_ParseWithOpts(value.c_str(), &return_parse_end, 1/*require_null_terminated*/); + + if (!m_value || cJSON_IsInvalid(m_value)) + { + m_wasParseSuccessful = false; + m_errorMessage = "Failed to parse JSON at: "; + m_errorMessage += return_parse_end; + } +} + +JsonValue::JsonValue(Aws::IStream& istream) : m_wasParseSuccessful(true) +{ + Aws::StringStream memoryStream; + std::copy(std::istreambuf_iterator<char>(istream), std::istreambuf_iterator<char>(), std::ostreambuf_iterator<char>(memoryStream)); + const char* return_parse_end; + const auto input = memoryStream.str(); + m_value = cJSON_ParseWithOpts(input.c_str(), &return_parse_end, 1/*require_null_terminated*/); + + if (!m_value || cJSON_IsInvalid(m_value)) + { + m_wasParseSuccessful = false; + m_errorMessage = "Failed to parse JSON. Invalid input at: "; + m_errorMessage += return_parse_end; + } +} + +JsonValue::JsonValue(const JsonValue& value) : + m_value(cJSON_Duplicate(value.m_value, true/*recurse*/)), + m_wasParseSuccessful(value.m_wasParseSuccessful), + m_errorMessage(value.m_errorMessage) +{ +} + +JsonValue::JsonValue(JsonValue&& value) : + m_value(value.m_value), + m_wasParseSuccessful(value.m_wasParseSuccessful), + m_errorMessage(std::move(value.m_errorMessage)) +{ + value.m_value = nullptr; +} + +void JsonValue::Destroy() +{ + cJSON_Delete(m_value); +} + +JsonValue::~JsonValue() +{ + Destroy(); +} + +JsonValue& JsonValue::operator=(const JsonValue& other) +{ + if (this == &other) + { + return *this; + } + + Destroy(); + m_value = cJSON_Duplicate(other.m_value, true /*recurse*/); + m_wasParseSuccessful = other.m_wasParseSuccessful; + m_errorMessage = other.m_errorMessage; + return *this; +} + +JsonValue& JsonValue::operator=(JsonValue&& other) +{ + if (this == &other) + { + return *this; + } + + using std::swap; + swap(m_value, other.m_value); + swap(m_errorMessage, other.m_errorMessage); + m_wasParseSuccessful = other.m_wasParseSuccessful; + return *this; +} + +static void AddOrReplace(cJSON* root, const char* key, cJSON* value) +{ + const auto existing = cJSON_GetObjectItemCaseSensitive(root, key); + if (existing) + { + cJSON_ReplaceItemInObjectCaseSensitive(root, key, value); + } + else + { + cJSON_AddItemToObject(root, key, value); + } +} + +JsonValue& JsonValue::WithString(const char* key, const Aws::String& value) +{ + if (!m_value) + { + m_value = cJSON_CreateObject(); + } + + const auto val = cJSON_CreateString(value.c_str()); + AddOrReplace(m_value, key, val); + return *this; +} + +JsonValue& JsonValue::WithString(const Aws::String& key, const Aws::String& value) +{ + return WithString(key.c_str(), value); +} + +JsonValue& JsonValue::AsString(const Aws::String& value) +{ + Destroy(); + m_value = cJSON_CreateString(value.c_str()); + return *this; +} + +JsonValue& JsonValue::WithBool(const char* key, bool value) +{ + if (!m_value) + { + m_value = cJSON_CreateObject(); + } + + const auto val = cJSON_CreateBool(value); + AddOrReplace(m_value, key, val); + return *this; +} + +JsonValue& JsonValue::WithBool(const Aws::String& key, bool value) +{ + return WithBool(key.c_str(), value); +} + +JsonValue& JsonValue::AsBool(bool value) +{ + Destroy(); + m_value = cJSON_CreateBool(value); + return *this; +} + +JsonValue& JsonValue::WithInteger(const char* key, int value) +{ + return WithDouble(key, static_cast<double>(value)); +} + +JsonValue& JsonValue::WithInteger(const Aws::String& key, int value) +{ + return WithDouble(key.c_str(), static_cast<double>(value)); +} + +JsonValue& JsonValue::AsInteger(int value) +{ + Destroy(); + m_value = cJSON_CreateNumber(static_cast<double>(value)); + return *this; +} + +JsonValue& JsonValue::WithInt64(const char* key, long long value) +{ + if (!m_value) + { + m_value = cJSON_CreateObject(); + } + + const auto val = cJSON_CreateInt64(value); + AddOrReplace(m_value, key, val); + return *this; +} + +JsonValue& JsonValue::WithInt64(const Aws::String& key, long long value) +{ + return WithInt64(key.c_str(), value); +} + +JsonValue& JsonValue::AsInt64(long long value) +{ + Destroy(); + m_value = cJSON_CreateInt64(value); + return *this; +} + +JsonValue& JsonValue::WithDouble(const char* key, double value) +{ + if (!m_value) + { + m_value = cJSON_CreateObject(); + } + + const auto val = cJSON_CreateNumber(value); + AddOrReplace(m_value, key, val); + return *this; +} + +JsonValue& JsonValue::WithDouble(const Aws::String& key, double value) +{ + return WithDouble(key.c_str(), value); +} + +JsonValue& JsonValue::AsDouble(double value) +{ + Destroy(); + m_value = cJSON_CreateNumber(value); + return *this; +} + +JsonValue& JsonValue::WithArray(const char* key, const Array<Aws::String>& array) +{ + if (!m_value) + { + m_value = cJSON_CreateObject(); + } + + auto arrayValue = cJSON_CreateArray(); + for (unsigned i = 0; i < array.GetLength(); ++i) + { + cJSON_AddItemToArray(arrayValue, cJSON_CreateString(array[i].c_str())); + } + + AddOrReplace(m_value, key, arrayValue); + return *this; +} + +JsonValue& JsonValue::WithArray(const Aws::String& key, const Array<Aws::String>& array) +{ + return WithArray(key.c_str(), array); +} + +JsonValue& JsonValue::WithArray(const Aws::String& key, const Array<JsonValue>& array) +{ + if (!m_value) + { + m_value = cJSON_CreateObject(); + } + + auto arrayValue = cJSON_CreateArray(); + for (unsigned i = 0; i < array.GetLength(); ++i) + { + cJSON_AddItemToArray(arrayValue, cJSON_Duplicate(array[i].m_value, true /*recurse*/)); + } + + AddOrReplace(m_value, key.c_str(), arrayValue); + return *this; +} + +JsonValue& JsonValue::WithArray(const Aws::String& key, Array<JsonValue>&& array) +{ + if (!m_value) + { + m_value = cJSON_CreateObject(); + } + + auto arrayValue = cJSON_CreateArray(); + for (unsigned i = 0; i < array.GetLength(); ++i) + { + cJSON_AddItemToArray(arrayValue, array[i].m_value); + array[i].m_value = nullptr; + } + + AddOrReplace(m_value, key.c_str(), arrayValue); + return *this; +} + +JsonValue& JsonValue::AsArray(const Array<JsonValue>& array) +{ + auto arrayValue = cJSON_CreateArray(); + for (unsigned i = 0; i < array.GetLength(); ++i) + { + cJSON_AddItemToArray(arrayValue, cJSON_Duplicate(array[i].m_value, true /*recurse*/)); + } + + Destroy(); + m_value = arrayValue; + return *this; +} + +JsonValue& JsonValue::AsArray(Array<JsonValue>&& array) +{ + auto arrayValue = cJSON_CreateArray(); + for (unsigned i = 0; i < array.GetLength(); ++i) + { + cJSON_AddItemToArray(arrayValue, array[i].m_value); + array[i].m_value = nullptr; + } + + Destroy(); + m_value = arrayValue; + return *this; +} + +JsonValue& JsonValue::WithObject(const char* key, const JsonValue& value) +{ + if (!m_value) + { + m_value = cJSON_CreateObject(); + } + + const auto copy = value.m_value == nullptr ? cJSON_CreateObject() : cJSON_Duplicate(value.m_value, true /*recurse*/); + AddOrReplace(m_value, key, copy); + return *this; +} + +JsonValue& JsonValue::WithObject(const Aws::String& key, const JsonValue& value) +{ + return WithObject(key.c_str(), value); +} + +JsonValue& JsonValue::WithObject(const char* key, JsonValue&& value) +{ + if (!m_value) + { + m_value = cJSON_CreateObject(); + } + + AddOrReplace(m_value, key, value.m_value == nullptr ? cJSON_CreateObject() : value.m_value); + value.m_value = nullptr; + return *this; +} + +JsonValue& JsonValue::WithObject(const Aws::String& key, JsonValue&& value) +{ + return WithObject(key.c_str(), std::move(value)); +} + +JsonValue& JsonValue::AsObject(const JsonValue& value) +{ + *this = value; + return *this; +} + +JsonValue& JsonValue::AsObject(JsonValue && value) +{ + *this = std::move(value); + return *this; +} + +bool JsonValue::operator==(const JsonValue& other) const +{ + return cJSON_Compare(m_value, other.m_value, true /*case-sensitive*/) != 0; +} + +bool JsonValue::operator!=(const JsonValue& other) const +{ + return !(*this == other); +} + +JsonView JsonValue::View() const +{ + return *this; +} + +JsonView::JsonView() : m_value(nullptr) +{ +} + +JsonView::JsonView(const JsonValue& val) : m_value(val.m_value) +{ +} + +JsonView::JsonView(cJSON* val) : m_value(val) +{ +} + +JsonView& JsonView::operator=(const JsonValue& v) +{ + m_value = v.m_value; + return *this; +} + +JsonView& JsonView::operator=(cJSON* val) +{ + m_value = val; + return *this; +} + +Aws::String JsonView::GetString(const Aws::String& key) const +{ + assert(m_value); + auto item = cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()); + auto str = cJSON_GetStringValue(item); + return str ? str : ""; +} + +Aws::String JsonView::AsString() const +{ + const char* str = cJSON_GetStringValue(m_value); + if (str == nullptr) + { + return {}; + } + return str; +} + +bool JsonView::GetBool(const Aws::String& key) const +{ + assert(m_value); + auto item = cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()); + assert(item); + return item->valueint != 0; +} + +bool JsonView::AsBool() const +{ + assert(cJSON_IsBool(m_value)); + return cJSON_IsTrue(m_value) != 0; +} + +int JsonView::GetInteger(const Aws::String& key) const +{ + assert(m_value); + auto item = cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()); + assert(item); + return item->valueint; +} + +int JsonView::AsInteger() const +{ + assert(cJSON_IsNumber(m_value)); // can be double or value larger than int_max, but at least not UB + return m_value->valueint; +} + +int64_t JsonView::GetInt64(const Aws::String& key) const +{ + assert(m_value); + auto item = cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()); + assert(item); + if (item->valuestring) + { + return Aws::Utils::StringUtils::ConvertToInt64(item->valuestring); + } + else + { + return static_cast<int64_t>(item->valuedouble); + } +} + +int64_t JsonView::AsInt64() const +{ + assert(cJSON_IsNumber(m_value)); + if (m_value->valuestring) + { + return Aws::Utils::StringUtils::ConvertToInt64(m_value->valuestring); + } + else + { + return static_cast<int64_t>(m_value->valuedouble); + } +} + +double JsonView::GetDouble(const Aws::String& key) const +{ + assert(m_value); + auto item = cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()); + assert(item); + return item->valuedouble; +} + +double JsonView::AsDouble() const +{ + assert(cJSON_IsNumber(m_value)); + return m_value->valuedouble; +} + +JsonView JsonView::GetObject(const Aws::String& key) const +{ + assert(m_value); + auto item = cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()); + return item; +} + +JsonView JsonView::AsObject() const +{ + assert(cJSON_IsObject(m_value) || cJSON_IsNull(m_value)); + return m_value; +} + +Array<JsonView> JsonView::GetArray(const Aws::String& key) const +{ + assert(m_value); + auto array = cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()); + assert(cJSON_IsArray(array)); + Array<JsonView> returnArray(cJSON_GetArraySize(array)); + + auto element = array->child; + for (unsigned i = 0; element && i < returnArray.GetLength(); ++i, element = element->next) + { + returnArray[i] = element; + } + + return returnArray; +} + +Array<JsonView> JsonView::AsArray() const +{ + assert(cJSON_IsArray(m_value)); + Array<JsonView> returnArray(cJSON_GetArraySize(m_value)); + + auto element = m_value->child; + + for (unsigned i = 0; element && i < returnArray.GetLength(); ++i, element = element->next) + { + returnArray[i] = element; + } + + return returnArray; +} + +Aws::Map<Aws::String, JsonView> JsonView::GetAllObjects() const +{ + Aws::Map<Aws::String, JsonView> valueMap; + if (!m_value) + { + return valueMap; + } + + for (auto iter = m_value->child; iter; iter = iter->next) + { + valueMap.emplace(std::make_pair(Aws::String(iter->string), JsonView(iter))); + } + + return valueMap; +} + +bool JsonView::ValueExists(const Aws::String& key) const +{ + if (!cJSON_IsObject(m_value)) + { + return false; + } + + auto item = cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()); + return !(item == nullptr || cJSON_IsNull(item)); +} + +bool JsonView::KeyExists(const Aws::String& key) const +{ + if (!cJSON_IsObject(m_value)) + { + return false; + } + + return cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()) != nullptr;; +} + +bool JsonView::IsObject() const +{ + return cJSON_IsObject(m_value) != 0; +} + +bool JsonView::IsBool() const +{ + return cJSON_IsBool(m_value) != 0; +} + +bool JsonView::IsString() const +{ + return cJSON_IsString(m_value) != 0; +} + +bool JsonView::IsIntegerType() const +{ + if (!cJSON_IsNumber(m_value)) + { + return false; + } + + if (m_value->valuestring) + { + Aws::String valueString = m_value->valuestring; + return std::all_of(valueString.begin(), valueString.end(), [](unsigned char c){ return ::isdigit(c) || c == '+' || c == '-'; }); + } + return m_value->valuedouble == static_cast<long long>(m_value->valuedouble); +} + +bool JsonView::IsFloatingPointType() const +{ + if (!cJSON_IsNumber(m_value)) + { + return false; + } + + if (m_value->valuestring) + { + Aws::String valueString = m_value->valuestring; + return std::any_of(valueString.begin(), valueString.end(), [](unsigned char c){ return !::isdigit(c) && c != '+' && c != '-'; }); + } + return m_value->valuedouble != static_cast<long long>(m_value->valuedouble); +} + +bool JsonView::IsListType() const +{ + return cJSON_IsArray(m_value) != 0; +} + +bool JsonView::IsNull() const +{ + return cJSON_IsNull(m_value) != 0; +} + +Aws::String JsonView::WriteCompact(bool treatAsObject) const +{ + if (!m_value) + { + if (treatAsObject) + { + return "{}"; + } + return {}; + } + + auto temp = cJSON_PrintUnformatted(m_value); + Aws::String out(temp); + cJSON_free(temp); + return out; +} + +Aws::String JsonView::WriteReadable(bool treatAsObject) const +{ + if (!m_value) + { + if (treatAsObject) + { + return "{\n}\n"; + } + return {}; + } + + auto temp = cJSON_Print(m_value); + Aws::String out(temp); + cJSON_free(temp); + return out; +} + +JsonValue JsonView::Materialize() const +{ + return m_value; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/AWSLogging.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/AWSLogging.cpp new file mode 100644 index 0000000000..fc1b9fcc2e --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/AWSLogging.cpp @@ -0,0 +1,51 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#include <aws/core/utils/logging/AWSLogging.h> +#include <aws/core/utils/logging/LogSystemInterface.h> +#include <aws/core/utils/memory/stl/AWSStack.h> + +#include <memory> + +using namespace Aws::Utils; +using namespace Aws::Utils::Logging; + +static std::shared_ptr<LogSystemInterface> AWSLogSystem(nullptr); +static std::shared_ptr<LogSystemInterface> OldLogger(nullptr); + +namespace Aws +{ +namespace Utils +{ +namespace Logging { + +void InitializeAWSLogging(const std::shared_ptr<LogSystemInterface> &logSystem) { + AWSLogSystem = logSystem; +} + +void ShutdownAWSLogging(void) { + InitializeAWSLogging(nullptr); +} + +LogSystemInterface *GetLogSystem() { + return AWSLogSystem.get(); +} + +void PushLogger(const std::shared_ptr<LogSystemInterface> &logSystem) +{ + OldLogger = AWSLogSystem; + AWSLogSystem = logSystem; +} + +void PopLogger() +{ + AWSLogSystem = OldLogger; + OldLogger = nullptr; +} + +} // namespace Logging +} // namespace Utils +} // namespace Aws
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/ConsoleLogSystem.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/ConsoleLogSystem.cpp new file mode 100644 index 0000000000..dec7cef82f --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/ConsoleLogSystem.cpp @@ -0,0 +1,22 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#include <aws/core/utils/logging/ConsoleLogSystem.h> + +#include <iostream> + +using namespace Aws::Utils; +using namespace Aws::Utils::Logging; + +void ConsoleLogSystem::ProcessFormattedStatement(Aws::String&& statement) +{ + std::cout << statement; +} + +void ConsoleLogSystem::Flush() +{ + std::cout.flush(); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/DefaultLogSystem.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/DefaultLogSystem.cpp new file mode 100644 index 0000000000..7286bb6378 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/DefaultLogSystem.cpp @@ -0,0 +1,117 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#include <aws/core/utils/logging/DefaultLogSystem.h> + +#include <aws/core/utils/DateTime.h> +#include <aws/core/utils/memory/stl/AWSVector.h> + +#include <fstream> + +using namespace Aws::Utils; +using namespace Aws::Utils::Logging; + +static const char* AllocationTag = "DefaultLogSystem"; +static const int BUFFERED_MSG_COUNT = 100; + +static std::shared_ptr<Aws::OFStream> MakeDefaultLogFile(const Aws::String& filenamePrefix) +{ + Aws::String newFileName = filenamePrefix + DateTime::CalculateGmtTimestampAsString("%Y-%m-%d-%H") + ".log"; + return Aws::MakeShared<Aws::OFStream>(AllocationTag, newFileName.c_str(), Aws::OFStream::out | Aws::OFStream::app); +} + +static void LogThread(DefaultLogSystem::LogSynchronizationData* syncData, const std::shared_ptr<Aws::OStream>& logFile, const Aws::String& filenamePrefix, bool rollLog) +{ + // localtime requires access to env. variables to get Timezone, which is not thread-safe + int32_t lastRolledHour = DateTime::Now().GetHour(false /*localtime*/); + std::shared_ptr<Aws::OStream> log = logFile; + + for(;;) + { + std::unique_lock<std::mutex> locker(syncData->m_logQueueMutex); + syncData->m_queueSignal.wait(locker, [&](){ return syncData->m_stopLogging == true || syncData->m_queuedLogMessages.size() > 0; } ); + + if (syncData->m_stopLogging && syncData->m_queuedLogMessages.size() == 0) + { + break; + } + + Aws::Vector<Aws::String> messages(std::move(syncData->m_queuedLogMessages)); + syncData->m_queuedLogMessages.reserve(BUFFERED_MSG_COUNT); + + locker.unlock(); + + if (messages.size() > 0) + { + if (rollLog) + { + // localtime requires access to env. variables to get Timezone, which is not thread-safe + int32_t currentHour = DateTime::Now().GetHour(false /*localtime*/); + if (currentHour != lastRolledHour) + { + log = MakeDefaultLogFile(filenamePrefix); + lastRolledHour = currentHour; + } + } + + for (const auto& msg : messages) + { + (*log) << msg; + } + + log->flush(); + } + } +} + +DefaultLogSystem::DefaultLogSystem(LogLevel logLevel, const std::shared_ptr<Aws::OStream>& logFile) : + Base(logLevel), + m_syncData(), + m_loggingThread() +{ + m_loggingThread = std::thread(LogThread, &m_syncData, logFile, "", false); +} + +DefaultLogSystem::DefaultLogSystem(LogLevel logLevel, const Aws::String& filenamePrefix) : + Base(logLevel), + m_syncData(), + m_loggingThread() +{ + m_loggingThread = std::thread(LogThread, &m_syncData, MakeDefaultLogFile(filenamePrefix), filenamePrefix, true); +} + +DefaultLogSystem::~DefaultLogSystem() +{ + { + std::lock_guard<std::mutex> locker(m_syncData.m_logQueueMutex); + m_syncData.m_stopLogging = true; + } + + m_syncData.m_queueSignal.notify_one(); + + m_loggingThread.join(); +} + +void DefaultLogSystem::ProcessFormattedStatement(Aws::String&& statement) +{ + std::unique_lock<std::mutex> locker(m_syncData.m_logQueueMutex); + m_syncData.m_queuedLogMessages.emplace_back(std::move(statement)); + if(m_syncData.m_queuedLogMessages.size() >= BUFFERED_MSG_COUNT) + { + locker.unlock(); + m_syncData.m_queueSignal.notify_one(); + } + else + { + locker.unlock(); + } +} + +void DefaultLogSystem::Flush() +{ + m_syncData.m_queueSignal.notify_one(); +} + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/FormattedLogSystem.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/FormattedLogSystem.cpp new file mode 100644 index 0000000000..41c4d7e09c --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/FormattedLogSystem.cpp @@ -0,0 +1,99 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#include <aws/core/utils/logging/FormattedLogSystem.h> + +#include <aws/core/utils/DateTime.h> +#include <aws/core/utils/Array.h> + +#include <fstream> +#include <cstdarg> +#include <stdio.h> +#include <thread> + +using namespace Aws::Utils; +using namespace Aws::Utils::Logging; + +static Aws::String CreateLogPrefixLine(LogLevel logLevel, const char* tag) +{ + Aws::StringStream ss; + + switch(logLevel) + { + case LogLevel::Error: + ss << "[ERROR] "; + break; + + case LogLevel::Fatal: + ss << "[FATAL] "; + break; + + case LogLevel::Warn: + ss << "[WARN] "; + break; + + case LogLevel::Info: + ss << "[INFO] "; + break; + + case LogLevel::Debug: + ss << "[DEBUG] "; + break; + + case LogLevel::Trace: + ss << "[TRACE] "; + break; + + default: + ss << "[UNKOWN] "; + break; + } + + ss << DateTime::Now().CalculateGmtTimeWithMsPrecision() << " " << tag << " [" << std::this_thread::get_id() << "] "; + + return ss.str(); +} + +FormattedLogSystem::FormattedLogSystem(LogLevel logLevel) : + m_logLevel(logLevel) +{ +} + +void FormattedLogSystem::Log(LogLevel logLevel, const char* tag, const char* formatStr, ...) +{ + Aws::StringStream ss; + ss << CreateLogPrefixLine(logLevel, tag); + + std::va_list args; + va_start(args, formatStr); + + va_list tmp_args; //unfortunately you cannot consume a va_list twice + va_copy(tmp_args, args); //so we have to copy it + #ifdef WIN32 + const int requiredLength = _vscprintf(formatStr, tmp_args) + 1; + #else + const int requiredLength = vsnprintf(nullptr, 0, formatStr, tmp_args) + 1; + #endif + va_end(tmp_args); + + Array<char> outputBuff(requiredLength); + #ifdef WIN32 + vsnprintf_s(outputBuff.GetUnderlyingData(), requiredLength, _TRUNCATE, formatStr, args); + #else + vsnprintf(outputBuff.GetUnderlyingData(), requiredLength, formatStr, args); + #endif // WIN32 + + ss << outputBuff.GetUnderlyingData() << std::endl; + + ProcessFormattedStatement(ss.str()); + + va_end(args); +} + +void FormattedLogSystem::LogStream(LogLevel logLevel, const char* tag, const Aws::OStringStream &message_stream) +{ + ProcessFormattedStatement(CreateLogPrefixLine(logLevel, tag) + message_stream.str() + "\n"); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/LogLevel.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/LogLevel.cpp new file mode 100644 index 0000000000..9ff1bf3126 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/LogLevel.cpp @@ -0,0 +1,45 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/logging/LogLevel.h> + +#include <aws/core/utils/memory/stl/AWSMap.h> +#include <aws/core/utils/memory/stl/AWSString.h> +#include <cassert> + +using namespace Aws::Utils::Logging; + +namespace Aws +{ +namespace Utils +{ +namespace Logging +{ + +Aws::String GetLogLevelName(LogLevel logLevel) +{ + switch (logLevel) + { + case LogLevel::Fatal: + return "FATAL"; + case LogLevel::Error: + return "ERROR"; + case LogLevel::Warn: + return "WARN"; + case LogLevel::Info: + return "INFO"; + case LogLevel::Debug: + return "DEBUG"; + case LogLevel::Trace: + return "TRACE"; + default: + assert(0); + return ""; + } +} + +} // namespace Logging +} // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/memory/AWSMemory.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/memory/AWSMemory.cpp new file mode 100644 index 0000000000..96d339d385 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/memory/AWSMemory.cpp @@ -0,0 +1,134 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/memory/AWSMemory.h> + +#include <aws/core/utils/memory/MemorySystemInterface.h> +#include <aws/common/common.h> + +#include <atomic> + +using namespace Aws::Utils; +using namespace Aws::Utils::Memory; + +#ifdef USE_AWS_MEMORY_MANAGEMENT + static MemorySystemInterface* AWSMemorySystem(nullptr); +#endif // USE_AWS_MEMORY_MANAGEMENT + +namespace Aws +{ +namespace Utils +{ +namespace Memory +{ + +void InitializeAWSMemorySystem(MemorySystemInterface& memorySystem) +{ + #ifdef USE_AWS_MEMORY_MANAGEMENT + if(AWSMemorySystem != nullptr) + { + AWSMemorySystem->End(); + } + + AWSMemorySystem = &memorySystem; + AWSMemorySystem->Begin(); + #else + AWS_UNREFERENCED_PARAM(memorySystem); + #endif // USE_AWS_MEMORY_MANAGEMENT +} + +void ShutdownAWSMemorySystem(void) +{ + #ifdef USE_AWS_MEMORY_MANAGEMENT + if(AWSMemorySystem != nullptr) + { + AWSMemorySystem->End(); + } + AWSMemorySystem = nullptr; + #endif // USE_AWS_MEMORY_MANAGEMENT +} + +MemorySystemInterface* GetMemorySystem() +{ + #ifdef USE_AWS_MEMORY_MANAGEMENT + return AWSMemorySystem; + #else + return nullptr; + #endif // USE_AWS_MEMORY_MANAGEMENT +} + +} // namespace Memory +} // namespace Utils + +void* Malloc(const char* allocationTag, size_t allocationSize) +{ + Aws::Utils::Memory::MemorySystemInterface* memorySystem = Aws::Utils::Memory::GetMemorySystem(); + + void* rawMemory = nullptr; + if(memorySystem != nullptr) + { + rawMemory = memorySystem->AllocateMemory(allocationSize, 1, allocationTag); + } + else + { + rawMemory = malloc(allocationSize); + } + + return rawMemory; +} + + +void Free(void* memoryPtr) +{ + if(memoryPtr == nullptr) + { + return; + } + + Aws::Utils::Memory::MemorySystemInterface* memorySystem = Aws::Utils::Memory::GetMemorySystem(); + if(memorySystem != nullptr) + { + memorySystem->FreeMemory(memoryPtr); + } + else + { + free(memoryPtr); + } +} + +static void* MemAcquire(aws_allocator* allocator, size_t size) +{ + (void)allocator; // unused; + return Aws::Malloc("MemAcquire", size); +} + +static void MemRelease(aws_allocator* allocator, void* ptr) +{ + (void)allocator; // unused; + return Aws::Free(ptr); +} + +static aws_allocator create_aws_allocator() +{ +#if (__GNUC__ == 4) && !defined(__clang__) + AWS_SUPPRESS_WARNING("-Wmissing-field-initializers", aws_allocator wrapper{};); +#else + aws_allocator wrapper{}; +#endif + wrapper.mem_acquire = MemAcquire; + wrapper.mem_release = MemRelease; + wrapper.mem_realloc = nullptr; + return wrapper; +} + +aws_allocator* get_aws_allocator() +{ + static aws_allocator wrapper = create_aws_allocator(); + return &wrapper; +} + +} // namespace Aws + + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/memory/stl/SimpleStringStream.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/memory/stl/SimpleStringStream.cpp new file mode 100644 index 0000000000..4662749872 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/memory/stl/SimpleStringStream.cpp @@ -0,0 +1,66 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/memory/stl/SimpleStringStream.h> + +namespace Aws +{ + +SimpleStringStream::SimpleStringStream() : + base(&m_streamBuffer), + m_streamBuffer() +{ +} + +SimpleStringStream::SimpleStringStream(const Aws::String& value) : + base(&m_streamBuffer), + m_streamBuffer(value) +{ +} + +void SimpleStringStream::str(const Aws::String& value) +{ + m_streamBuffer.str(value); +} + +// + +SimpleIStringStream::SimpleIStringStream() : + base(&m_streamBuffer), + m_streamBuffer() +{ +} + +SimpleIStringStream::SimpleIStringStream(const Aws::String& value) : + base(&m_streamBuffer), + m_streamBuffer(value) +{ +} + +void SimpleIStringStream::str(const Aws::String& value) +{ + m_streamBuffer.str(value); +} + +// + +SimpleOStringStream::SimpleOStringStream() : + base(&m_streamBuffer), + m_streamBuffer() +{ +} + +SimpleOStringStream::SimpleOStringStream(const Aws::String& value) : + base(&m_streamBuffer), + m_streamBuffer(value) +{ +} + +void SimpleOStringStream::str(const Aws::String& value) +{ + m_streamBuffer.str(value); +} + +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/ConcurrentStreamBuf.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/ConcurrentStreamBuf.cpp new file mode 100644 index 0000000000..3f59dbe96d --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/ConcurrentStreamBuf.cpp @@ -0,0 +1,126 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include <aws/core/utils/stream/ConcurrentStreamBuf.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <cstdint> +#include <cassert> + +namespace Aws +{ + namespace Utils + { + namespace Stream + { + const char TAG[] = "ConcurrentStreamBuf"; + ConcurrentStreamBuf::ConcurrentStreamBuf(size_t bufferLength) : + m_putArea(bufferLength), // we access [0] of the put area below so we must initialize it. + m_eof(false) + { + m_getArea.reserve(bufferLength); + m_backbuf.reserve(bufferLength); + + char* pbegin = reinterpret_cast<char*>(&m_putArea[0]); + setp(pbegin, pbegin + bufferLength); + } + + void ConcurrentStreamBuf::SetEof() + { + { + std::unique_lock<std::mutex> lock(m_lock); + m_eof = true; + } + m_signal.notify_all(); + } + + void ConcurrentStreamBuf::FlushPutArea() + { + const size_t bitslen = pptr() - pbase(); + if (bitslen) + { + // scope the lock + { + std::unique_lock<std::mutex> lock(m_lock); + m_signal.wait(lock, [this, bitslen]{ return m_eof || bitslen <= (m_backbuf.capacity() - m_backbuf.size()); }); + if (m_eof) + { + return; + } + std::copy(pbase(), pptr(), std::back_inserter(m_backbuf)); + } + m_signal.notify_one(); + char* pbegin = reinterpret_cast<char*>(&m_putArea[0]); + setp(pbegin, pbegin + m_putArea.size()); + } + } + + std::streampos ConcurrentStreamBuf::seekoff(std::streamoff, std::ios_base::seekdir, std::ios_base::openmode) + { + return std::streamoff(-1); // Seeking is not supported. + } + + std::streampos ConcurrentStreamBuf::seekpos(std::streampos, std::ios_base::openmode) + { + return std::streamoff(-1); // Seeking is not supported. + } + + int ConcurrentStreamBuf::underflow() + { + { + std::unique_lock<std::mutex> lock(m_lock); + m_signal.wait(lock, [this]{ return m_backbuf.empty() == false || m_eof; }); + + if (m_eof && m_backbuf.empty()) + { + return std::char_traits<char>::eof(); + } + + m_getArea.clear(); // keep the get-area from growing unbounded. + std::copy(m_backbuf.begin(), m_backbuf.end(), std::back_inserter(m_getArea)); + m_backbuf.clear(); + } + m_signal.notify_one(); + char* gbegin = reinterpret_cast<char*>(&m_getArea[0]); + setg(gbegin, gbegin, gbegin + m_getArea.size()); + return std::char_traits<char>::to_int_type(*gptr()); + } + + std::streamsize ConcurrentStreamBuf::showmanyc() + { + std::unique_lock<std::mutex> lock(m_lock); + AWS_LOGSTREAM_TRACE(TAG, "stream how many character? " << m_backbuf.size()); + return m_backbuf.size(); + } + + int ConcurrentStreamBuf::overflow(int ch) + { + const auto eof = std::char_traits<char>::eof(); + + if (ch == eof) + { + FlushPutArea(); + return eof; + } + + FlushPutArea(); + { + std::unique_lock<std::mutex> lock(m_lock); + if (m_eof) + { + return eof; + } + *pptr() = static_cast<char>(ch); + pbump(1); + return ch; + } + } + + int ConcurrentStreamBuf::sync() + { + FlushPutArea(); + return 0; + } + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/PreallocatedStreamBuf.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/PreallocatedStreamBuf.cpp new file mode 100644 index 0000000000..f656fc8613 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/PreallocatedStreamBuf.cpp @@ -0,0 +1,75 @@ + +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/stream/PreallocatedStreamBuf.h> +#include <cassert> + +namespace Aws +{ + namespace Utils + { + namespace Stream + { + PreallocatedStreamBuf::PreallocatedStreamBuf(unsigned char* buffer, uint64_t lengthToRead) : + m_underlyingBuffer(buffer), m_lengthToRead(lengthToRead) + { + char* end = reinterpret_cast<char*>(m_underlyingBuffer + m_lengthToRead); + char* begin = reinterpret_cast<char*>(m_underlyingBuffer); + setp(begin, end); + setg(begin, begin, end); + } + + PreallocatedStreamBuf::pos_type PreallocatedStreamBuf::seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which) + { + if (dir == std::ios_base::beg) + { + return seekpos(off, which); + } + else if (dir == std::ios_base::end) + { + return seekpos(m_lengthToRead - off, which); + } + else if (dir == std::ios_base::cur) + { + if(which == std::ios_base::in) + { + return seekpos((gptr() - reinterpret_cast<char*>(m_underlyingBuffer)) + off, which); + } + else + { + return seekpos((pptr() - reinterpret_cast<char*>(m_underlyingBuffer)) + off, which); + } + } + + return off_type(-1); + } + + PreallocatedStreamBuf::pos_type PreallocatedStreamBuf::seekpos(pos_type pos, std::ios_base::openmode which) + { + assert(static_cast<size_t>(pos) <= m_lengthToRead); + if (static_cast<size_t>(pos) > m_lengthToRead) + { + return pos_type(off_type(-1)); + } + + char* end = reinterpret_cast<char*>(m_underlyingBuffer + m_lengthToRead); + char* begin = reinterpret_cast<char*>(m_underlyingBuffer); + + if (which == std::ios_base::in) + { + setg(begin, begin + static_cast<size_t>(pos), end); + } + + if (which == std::ios_base::out) + { + setp(begin + static_cast<size_t>(pos), end); + } + + return pos; + } + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/ResponseStream.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/ResponseStream.cpp new file mode 100644 index 0000000000..6d1f90ed12 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/ResponseStream.cpp @@ -0,0 +1,91 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/stream/ResponseStream.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> + +#if defined(_GLIBCXX_FULLY_DYNAMIC_STRING) && _GLIBCXX_FULLY_DYNAMIC_STRING == 0 && defined(__ANDROID__) +#include <aws/core/utils/stream/SimpleStreamBuf.h> +using DefaultStreamBufType = Aws::Utils::Stream::SimpleStreamBuf; +#else +using DefaultStreamBufType = Aws::StringBuf; +#endif + +using namespace Aws::Utils::Stream; + +ResponseStream::ResponseStream(void) : + m_underlyingStream(nullptr) +{ +} + +ResponseStream::ResponseStream(Aws::IOStream* underlyingStreamToManage) : + m_underlyingStream(underlyingStreamToManage) +{ +} + +ResponseStream::ResponseStream(const Aws::IOStreamFactory& factory) : + m_underlyingStream(factory()) +{ +} + +ResponseStream::ResponseStream(ResponseStream&& toMove) : m_underlyingStream(toMove.m_underlyingStream) +{ + toMove.m_underlyingStream = nullptr; +} + +ResponseStream& ResponseStream::operator=(ResponseStream&& toMove) +{ + if(m_underlyingStream == toMove.m_underlyingStream) + { + return *this; + } + + ReleaseStream(); + m_underlyingStream = toMove.m_underlyingStream; + toMove.m_underlyingStream = nullptr; + + return *this; +} + +ResponseStream::~ResponseStream() +{ + ReleaseStream(); +} + +void ResponseStream::ReleaseStream() +{ + if (m_underlyingStream) + { + m_underlyingStream->flush(); + Aws::Delete(m_underlyingStream); + } + + m_underlyingStream = nullptr; +} + +static const char *DEFAULT_STREAM_TAG = "DefaultUnderlyingStream"; + +DefaultUnderlyingStream::DefaultUnderlyingStream() : + Base( Aws::New< DefaultStreamBufType >( DEFAULT_STREAM_TAG ) ) +{} + +DefaultUnderlyingStream::DefaultUnderlyingStream(Aws::UniquePtr<std::streambuf> buf) : + Base(buf.release()) +{} + +DefaultUnderlyingStream::~DefaultUnderlyingStream() +{ + if( rdbuf() ) + { + Aws::Delete( rdbuf() ); + } +} + +static const char* RESPONSE_STREAM_FACTORY_TAG = "ResponseStreamFactory"; + +Aws::IOStream* Aws::Utils::Stream::DefaultResponseStreamFactoryMethod() +{ + return Aws::New<Aws::Utils::Stream::DefaultUnderlyingStream>(RESPONSE_STREAM_FACTORY_TAG); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/SimpleStreamBuf.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/SimpleStreamBuf.cpp new file mode 100644 index 0000000000..6e42994744 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/SimpleStreamBuf.cpp @@ -0,0 +1,239 @@ + +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/stream/SimpleStreamBuf.h> + +#include <algorithm> +#include <cassert> +#include <cstring> + +namespace Aws +{ +namespace Utils +{ +namespace Stream +{ + +static const uint32_t DEFAULT_BUFFER_SIZE = 100; +static const char* SIMPLE_STREAMBUF_ALLOCATION_TAG = "SimpleStreamBufTag"; + +SimpleStreamBuf::SimpleStreamBuf() : + m_buffer(nullptr), + m_bufferSize(0) +{ + m_buffer = Aws::NewArray<char>(DEFAULT_BUFFER_SIZE, SIMPLE_STREAMBUF_ALLOCATION_TAG); + m_bufferSize = DEFAULT_BUFFER_SIZE; + + char* begin = m_buffer; + char* end = begin + m_bufferSize; + + setp(begin, end); + setg(begin, begin, begin); +} + +SimpleStreamBuf::SimpleStreamBuf(const Aws::String& value) : + m_buffer(nullptr), + m_bufferSize(0) +{ + size_t baseSize = (std::max)(value.size(), static_cast<std::size_t>(DEFAULT_BUFFER_SIZE)); + + m_buffer = Aws::NewArray<char>(baseSize, SIMPLE_STREAMBUF_ALLOCATION_TAG); + m_bufferSize = baseSize; + + std::memcpy(m_buffer, value.c_str(), value.size()); + + char* begin = m_buffer; + char* end = begin + m_bufferSize; + + setp(begin + value.size(), end); + setg(begin, begin, begin); +} + +SimpleStreamBuf::~SimpleStreamBuf() +{ + if(m_buffer) + { + Aws::DeleteArray<char>(m_buffer); + m_buffer = nullptr; + } + + m_bufferSize = 0; +} + +std::streampos SimpleStreamBuf::seekoff(std::streamoff off, std::ios_base::seekdir dir, std::ios_base::openmode which) +{ + if (dir == std::ios_base::beg) + { + return seekpos(off, which); + } + else if (dir == std::ios_base::end) + { + return seekpos((pptr() - m_buffer) - off, which); + } + else if (dir == std::ios_base::cur) + { + if(which == std::ios_base::in) + { + return seekpos((gptr() - m_buffer) + off, which); + } + else + { + return seekpos((pptr() - m_buffer) + off, which); + } + } + + return off_type(-1); +} + +std::streampos SimpleStreamBuf::seekpos(std::streampos pos, std::ios_base::openmode which) +{ + size_t maxSeek = pptr() - m_buffer; + assert(static_cast<size_t>(pos) <= maxSeek); + if (static_cast<size_t>(pos) > maxSeek) + { + return pos_type(off_type(-1)); + } + + if (which == std::ios_base::in) + { + setg(m_buffer, m_buffer + static_cast<size_t>(pos), pptr()); + } + + if (which == std::ios_base::out) + { + setp(m_buffer + static_cast<size_t>(pos), epptr()); + } + + return pos; +} + +bool SimpleStreamBuf::GrowBuffer() +{ + size_t currentSize = m_bufferSize; + size_t newSize = currentSize * 2; + + char* newBuffer = Aws::NewArray<char>(newSize, SIMPLE_STREAMBUF_ALLOCATION_TAG); + if(newBuffer == nullptr) + { + return false; + } + + if(currentSize > 0) + { + std::memcpy(newBuffer, m_buffer, currentSize); + } + + if(m_buffer) + { + Aws::DeleteArray<char>(m_buffer); + } + + m_buffer = newBuffer; + m_bufferSize = newSize; + + return true; +} + +int SimpleStreamBuf::overflow (int c) +{ + auto endOfFile = std::char_traits< char >::eof(); + if(c == endOfFile) + { + return endOfFile; + } + + char* old_begin = m_buffer; + + char *old_pptr = pptr(); + char *old_gptr = gptr(); + char *old_egptr = egptr(); + + size_t currentWritePosition = m_bufferSize; + + if(!GrowBuffer()) + { + return endOfFile; + } + + char* new_begin = m_buffer; + char* new_end = new_begin + m_bufferSize; + + setp(new_begin + (old_pptr - old_begin) + 1, new_end); + setg(new_begin, new_begin + (old_gptr - old_begin), new_begin + (old_egptr - old_begin)); + + auto val = std::char_traits< char >::to_char_type(c); + *(new_begin + currentWritePosition) = val; + + return c; +} + +std::streamsize SimpleStreamBuf::xsputn(const char* s, std::streamsize n) +{ + std::streamsize writeCount = 0; + while(writeCount < n) + { + char* current_pptr = pptr(); + char* current_epptr = epptr(); + + if (current_pptr < current_epptr) + { + std::size_t copySize = (std::min)(static_cast< std::size_t >(n - writeCount), + static_cast< std::size_t >(current_epptr - current_pptr)); + + std::memcpy(current_pptr, s + writeCount, copySize); + writeCount += copySize; + setp(current_pptr + copySize, current_epptr); + setg(m_buffer, gptr(), pptr()); + } + else if (overflow(std::char_traits< char >::to_int_type(*(s + writeCount))) != std::char_traits<char>::eof()) + { + writeCount++; + } + else + { + return writeCount; + } + } + + return writeCount; +} + +Aws::String SimpleStreamBuf::str() const +{ + return Aws::String(m_buffer, pptr()); +} + +int SimpleStreamBuf::underflow() +{ + if(egptr() != pptr()) + { + setg(m_buffer, gptr(), pptr()); + } + + if(gptr() != egptr()) + { + return std::char_traits< char >::to_int_type(*gptr()); + } + else + { + return std::char_traits< char >::eof(); + } +} + +void SimpleStreamBuf::str(const Aws::String& value) +{ + char* begin = m_buffer; + char* end = begin + m_bufferSize; + + setp(begin, end); + setg(begin, begin, begin); + + xsputn(value.c_str(), value.size()); +} + +} +} +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/threading/Executor.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/threading/Executor.cpp new file mode 100644 index 0000000000..4a3c4209c4 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/threading/Executor.cpp @@ -0,0 +1,155 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/threading/Executor.h> +#include <aws/core/utils/threading/ThreadTask.h> +#include <thread> +#include <cassert> + +static const char* POOLED_CLASS_TAG = "PooledThreadExecutor"; + +using namespace Aws::Utils::Threading; + +bool DefaultExecutor::SubmitToThread(std::function<void()>&& fx) +{ + auto main = [fx, this] { + fx(); + Detach(std::this_thread::get_id()); + }; + + State expected; + do + { + expected = State::Free; + if(m_state.compare_exchange_strong(expected, State::Locked)) + { + std::thread t(main); + const auto id = t.get_id(); // copy the id before we std::move the thread + m_threads.emplace(id, std::move(t)); + m_state = State::Free; + return true; + } + } + while(expected != State::Shutdown); + return false; +} + +void DefaultExecutor::Detach(std::thread::id id) +{ + State expected; + do + { + expected = State::Free; + if(m_state.compare_exchange_strong(expected, State::Locked)) + { + auto it = m_threads.find(id); + assert(it != m_threads.end()); + it->second.detach(); + m_threads.erase(it); + m_state = State::Free; + return; + } + } + while(expected != State::Shutdown); +} + +DefaultExecutor::~DefaultExecutor() +{ + auto expected = State::Free; + while(!m_state.compare_exchange_strong(expected, State::Shutdown)) + { + //spin while currently detaching threads finish + assert(expected == State::Locked); + expected = State::Free; + } + + auto it = m_threads.begin(); + while(!m_threads.empty()) + { + it->second.join(); + it = m_threads.erase(it); + } +} + +PooledThreadExecutor::PooledThreadExecutor(size_t poolSize, OverflowPolicy overflowPolicy) : + m_sync(0, poolSize), m_poolSize(poolSize), m_overflowPolicy(overflowPolicy) +{ + for (size_t index = 0; index < m_poolSize; ++index) + { + m_threadTaskHandles.push_back(Aws::New<ThreadTask>(POOLED_CLASS_TAG, *this)); + } +} + +PooledThreadExecutor::~PooledThreadExecutor() +{ + for(auto threadTask : m_threadTaskHandles) + { + threadTask->StopProcessingWork(); + } + + m_sync.ReleaseAll(); + + for (auto threadTask : m_threadTaskHandles) + { + Aws::Delete(threadTask); + } + + while(m_tasks.size() > 0) + { + std::function<void()>* fn = m_tasks.front(); + m_tasks.pop(); + + if(fn) + { + Aws::Delete(fn); + } + } + +} + +bool PooledThreadExecutor::SubmitToThread(std::function<void()>&& fn) +{ + //avoid the need to do copies inside the lock. Instead lets do a pointer push. + std::function<void()>* fnCpy = Aws::New<std::function<void()>>(POOLED_CLASS_TAG, std::forward<std::function<void()>>(fn)); + + { + std::lock_guard<std::mutex> locker(m_queueLock); + + if (m_overflowPolicy == OverflowPolicy::REJECT_IMMEDIATELY && m_tasks.size() >= m_poolSize) + { + Aws::Delete(fnCpy); + return false; + } + + m_tasks.push(fnCpy); + } + + m_sync.Release(); + + return true; +} + +std::function<void()>* PooledThreadExecutor::PopTask() +{ + std::lock_guard<std::mutex> locker(m_queueLock); + + if (m_tasks.size() > 0) + { + std::function<void()>* fn = m_tasks.front(); + if (fn) + { + m_tasks.pop(); + return fn; + } + } + + return nullptr; +} + +bool PooledThreadExecutor::HasTasks() +{ + std::lock_guard<std::mutex> locker(m_queueLock); + return m_tasks.size() > 0; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/threading/ReaderWriterLock.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/threading/ReaderWriterLock.cpp new file mode 100644 index 0000000000..ddb5860563 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/threading/ReaderWriterLock.cpp @@ -0,0 +1,64 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/threading/ReaderWriterLock.h> +#include <cstdint> +#include <limits> +#include <cassert> + +using namespace Aws::Utils::Threading; + +static const int64_t MaxReaders = (std::numeric_limits<std::int32_t>::max)(); + +ReaderWriterLock::ReaderWriterLock() : + m_readers(0), + m_holdouts(0), + m_readerSem(0, static_cast<size_t>(MaxReaders)), + m_writerSem(0, 1) +{ +} + +void ReaderWriterLock::LockReader() +{ + if (++m_readers < 0) + { + m_readerSem.WaitOne(); + } +} + +void ReaderWriterLock::UnlockReader() +{ + if (--m_readers < 0 && --m_holdouts == 0) + { + m_writerSem.Release(); + } +} + +void ReaderWriterLock::LockWriter() +{ + m_writerLock.lock(); + if(const auto current = m_readers.fetch_sub(MaxReaders)) + { + assert(current > 0); + const auto holdouts = m_holdouts.fetch_add(current) + current; + assert(holdouts >= 0); + if(holdouts > 0) + { + m_writerSem.WaitOne(); + } + } +} + +void ReaderWriterLock::UnlockWriter() +{ + assert(m_holdouts == 0); + const auto current = m_readers.fetch_add(MaxReaders) + MaxReaders; + assert(current >= 0); + for(int64_t r = 0; r < current; r++) + { + m_readerSem.Release(); + } + m_writerLock.unlock(); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/threading/Semaphore.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/threading/Semaphore.cpp new file mode 100644 index 0000000000..86dabc9acf --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/threading/Semaphore.cpp @@ -0,0 +1,39 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/threading/Semaphore.h> +#include <algorithm> + +using namespace Aws::Utils::Threading; + +Semaphore::Semaphore(size_t initialCount, size_t maxCount) + : m_count(initialCount), m_maxCount(maxCount) +{ +} + +void Semaphore::WaitOne() +{ + std::unique_lock<std::mutex> locker(m_mutex); + if(0 == m_count) + { + m_syncPoint.wait(locker, [this] { return m_count > 0; }); + } + --m_count; +} + +void Semaphore::Release() +{ + std::lock_guard<std::mutex> locker(m_mutex); + m_count = (std::min)(m_maxCount, m_count + 1); + m_syncPoint.notify_one(); +} + +void Semaphore::ReleaseAll() +{ + std::lock_guard<std::mutex> locker(m_mutex); + m_count = m_maxCount; + m_syncPoint.notify_all(); +} + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/threading/ThreadTask.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/threading/ThreadTask.cpp new file mode 100644 index 0000000000..a899fe045d --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/threading/ThreadTask.cpp @@ -0,0 +1,46 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/threading/ThreadTask.h> +#include <aws/core/utils/threading/Executor.h> + +using namespace Aws::Utils; +using namespace Aws::Utils::Threading; + +ThreadTask::ThreadTask(PooledThreadExecutor& executor) : m_continue(true), m_executor(executor), m_thread(std::bind(&ThreadTask::MainTaskRunner, this)) +{ +} + +ThreadTask::~ThreadTask() +{ + StopProcessingWork(); + m_thread.join(); +} + +void ThreadTask::MainTaskRunner() +{ + while (m_continue) + { + while (m_continue && m_executor.HasTasks()) + { + auto fn = m_executor.PopTask(); + if(fn) + { + (*fn)(); + Aws::Delete(fn); + } + } + + if(m_continue) + { + m_executor.m_sync.WaitOne(); + } + } +} + +void ThreadTask::StopProcessingWork() +{ + m_continue = false; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/xml/XmlSerializer.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/xml/XmlSerializer.cpp new file mode 100644 index 0000000000..c06befaf9b --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/xml/XmlSerializer.cpp @@ -0,0 +1,302 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/xml/XmlSerializer.h> + +#include <aws/core/utils/StringUtils.h> +#include <aws/core/external/tinyxml2/tinyxml2.h> + +#include <utility> +#include <algorithm> +#include <iostream> + +using namespace Aws::Utils::Xml; +using namespace Aws::Utils; + +Aws::String Aws::Utils::Xml::DecodeEscapedXmlText(const Aws::String& textToDecode) +{ + Aws::String decodedString = textToDecode; + StringUtils::Replace(decodedString, """, "\""); + StringUtils::Replace(decodedString, "'", "'"); + StringUtils::Replace(decodedString, "<", "<"); + StringUtils::Replace(decodedString, ">", ">"); + StringUtils::Replace(decodedString, "&", "&"); + + return decodedString; +} + +XmlNode::XmlNode(const XmlNode& other) : m_node(other.m_node), m_doc(other.m_doc) +{ +} + +XmlNode& XmlNode::operator=(const XmlNode& other) +{ + if(this == &other) + { + return *this; + } + + m_node = other.m_node; + m_doc = other.m_doc; + + return *this; +} + +const Aws::String XmlNode::GetName() const +{ + return m_node->Value(); +} + +void XmlNode::SetName(const Aws::String& name) +{ + m_node->SetValue(name.c_str(), false); +} + +const Aws::String XmlNode::GetAttributeValue(const Aws::String& name) const +{ + auto pointer = m_node->ToElement()->Attribute(name.c_str(), nullptr); + return pointer ? pointer : ""; +} + +void XmlNode::SetAttributeValue(const Aws::String& name, const Aws::String& value) +{ + m_node->ToElement()->SetAttribute(name.c_str(), value.c_str()); +} + +bool XmlNode::HasNextNode() const +{ + return m_node->NextSibling() != nullptr; +} + +XmlNode XmlNode::NextNode() const +{ + return XmlNode(m_node->NextSiblingElement(), *m_doc); +} + +XmlNode XmlNode::NextNode(const char* name) const +{ + return XmlNode(m_node->NextSiblingElement(name), *m_doc); +} + +XmlNode XmlNode::NextNode(const Aws::String& name) const +{ + return NextNode(name.c_str()); +} + +XmlNode XmlNode::FirstChild() const +{ + return XmlNode(m_node->FirstChildElement(), *m_doc); +} + +XmlNode XmlNode::FirstChild(const char* name) const +{ + return XmlNode(m_node->FirstChildElement(name), *m_doc); +} + +XmlNode XmlNode::FirstChild(const Aws::String& name) const +{ + return FirstChild(name.c_str()); +} + +bool XmlNode::HasChildren() const +{ + return !m_node->NoChildren(); +} + +XmlNode XmlNode::Parent() const +{ + return XmlNode(m_node->Parent()->ToElement(), *m_doc); +} + +Aws::String XmlNode::GetText() const +{ + if (m_node != nullptr) + { + Aws::External::tinyxml2::XMLPrinter printer; + Aws::External::tinyxml2::XMLNode* node = m_node->FirstChild(); + while (node != nullptr) + { + node->Accept(&printer); + node = node->NextSibling(); + } + + return printer.CStr(); + } + + return {}; +} + +void XmlNode::SetText(const Aws::String& textValue) +{ + if (m_node != nullptr) + { + Aws::External::tinyxml2::XMLText* text = m_doc->m_doc->NewText(textValue.c_str()); + m_node->InsertEndChild(text); + } +} + +XmlNode XmlNode::CreateChildElement(const Aws::String& name) +{ + Aws::External::tinyxml2::XMLElement* element = m_doc->m_doc->NewElement(name.c_str()); + return XmlNode(m_node->InsertEndChild(element), *m_doc); +} + +XmlNode XmlNode::CreateSiblingElement(const Aws::String& name) +{ + Aws::External::tinyxml2::XMLElement* element = m_doc->m_doc->NewElement(name.c_str()); + return XmlNode(m_node->Parent()->InsertEndChild(element), *m_doc); +} + +bool XmlNode::IsNull() +{ + return m_node == nullptr; +} + +static const char* XML_SERIALIZER_ALLOCATION_TAG = "XmlDocument"; + +XmlDocument::XmlDocument() +{ + m_doc = nullptr; +} + +XmlDocument::XmlDocument(const XmlDocument& doc) +{ + if (doc.m_doc == nullptr) + { + m_doc = nullptr; + } + else + { + InitDoc(); + doc.m_doc->DeepCopy(m_doc); + } +} + +XmlDocument::XmlDocument(XmlDocument&& doc) : m_doc{ doc.m_doc } // take the innards +{ + doc.m_doc = nullptr; // leave nothing behind +} + +XmlDocument& XmlDocument::operator=(const XmlDocument& other) +{ + if (this == &other) + { + return *this; + } + + if (other.m_doc == nullptr) + { + if (m_doc != nullptr) + { + m_doc->Clear(); + m_doc = nullptr; + } + } + else + { + if (m_doc == nullptr) + { + InitDoc(); + } + else + { + m_doc->Clear(); + } + other.m_doc->DeepCopy(m_doc); + } + + return *this; +} + +XmlDocument& XmlDocument::operator=(XmlDocument&& other) +{ + if (this == &other) + { + return *this; + } + + std::swap(m_doc, other.m_doc); + return *this; +} + +XmlDocument::~XmlDocument() +{ + if (m_doc) + { + Aws::Delete(m_doc); + } +} + +void XmlDocument::InitDoc() +{ + m_doc = Aws::New<Aws::External::tinyxml2::XMLDocument>(XML_SERIALIZER_ALLOCATION_TAG, true, Aws::External::tinyxml2::Whitespace::PRESERVE_WHITESPACE); +} + +XmlNode XmlDocument::GetRootElement() const +{ + if (m_doc) + { + return XmlNode(m_doc->FirstChildElement(), *this); + } + else + { + return XmlNode(nullptr, *this); + } + +} + +bool XmlDocument::WasParseSuccessful() const +{ + if (m_doc) + { + return !m_doc->Error(); + } + else + { + return true; + } + +} + +Aws::String XmlDocument::GetErrorMessage() const +{ + return !WasParseSuccessful() ? m_doc->ErrorName() : ""; +} + +Aws::String XmlDocument::ConvertToString() const +{ + if (!m_doc) return ""; + + Aws::External::tinyxml2::XMLPrinter printer; + printer.PushHeader(false, true); + m_doc->Accept(&printer); + + return printer.CStr(); +} + +XmlDocument XmlDocument::CreateFromXmlStream(Aws::IOStream& xmlStream) +{ + Aws::String xmlString((Aws::IStreamBufIterator(xmlStream)), Aws::IStreamBufIterator()); + return CreateFromXmlString(xmlString); +} + +XmlDocument XmlDocument::CreateFromXmlString(const Aws::String& xmlText) +{ + XmlDocument xmlDocument; + xmlDocument.InitDoc(); + xmlDocument.m_doc->Parse(xmlText.c_str(), xmlText.size()); + return xmlDocument; +} + +XmlDocument XmlDocument::CreateWithRootNode(const Aws::String& rootNodeName) +{ + XmlDocument xmlDocument; + xmlDocument.InitDoc(); + Aws::External::tinyxml2::XMLElement* rootNode = xmlDocument.m_doc->NewElement(rootNodeName.c_str()); + xmlDocument.m_doc->LinkEndChild(rootNode); + + return xmlDocument; +} + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/ya.make b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/ya.make new file mode 100644 index 0000000000..d6b0823d45 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/ya.make @@ -0,0 +1,154 @@ +# Generated by devtools/yamaker. + +LIBRARY() + +OWNER( + orivej + shindo + g:cpp-contrib +) + +LICENSE( + Apache-2.0 AND + MIT AND + Zlib +) + +LICENSE_TEXTS(.yandex_meta/licenses.list.txt) + +PEERDIR( + contrib/libs/curl + contrib/libs/openssl + contrib/restricted/aws/aws-c-common + contrib/restricted/aws/aws-c-event-stream +) + +ADDINCL( + GLOBAL contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/include +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +CFLAGS( + -DAWS_CAL_USE_IMPORT_EXPORT + -DAWS_CHECKSUMS_USE_IMPORT_EXPORT + -DAWS_COMMON_USE_IMPORT_EXPORT + -DAWS_EVENT_STREAM_USE_IMPORT_EXPORT + -DAWS_IO_USE_IMPORT_EXPORT + -DAWS_SDK_VERSION_MAJOR=1 + -DAWS_SDK_VERSION_MINOR=8 + -DAWS_SDK_VERSION_PATCH=113 + -DAWS_USE_EPOLL + -DCURL_HAS_H2 + -DCURL_HAS_TLS_PROXY + -DENABLE_CURL_CLIENT + -DENABLE_CURL_LOGGING + -DENABLE_OPENSSL_ENCRYPTION + -DHAS_PATHCONF + -DHAS_UMASK + -DS2N_ADX + -DS2N_CPUID_AVAILABLE + -DS2N_HAVE_EXECINFO + -DS2N_SIKEP434R2_ASM +) + +SRCS( + source/AmazonSerializableWebServiceRequest.cpp + source/AmazonStreamingWebServiceRequest.cpp + source/AmazonWebServiceRequest.cpp + source/Aws.cpp + source/Globals.cpp + source/Region.cpp + source/Version.cpp + source/auth/AWSAuthSigner.cpp + source/auth/AWSAuthSignerProvider.cpp + source/auth/AWSCredentialsProvider.cpp + source/auth/AWSCredentialsProviderChain.cpp + source/auth/STSCredentialsProvider.cpp + source/client/AWSClient.cpp + source/client/AWSErrorMarshaller.cpp + source/client/AsyncCallerContext.cpp + source/client/ClientConfiguration.cpp + source/client/CoreErrors.cpp + source/client/DefaultRetryStrategy.cpp + source/client/RetryStrategy.cpp + source/client/SpecifiedRetryableErrorsRetryStrategy.cpp + source/config/AWSProfileConfigLoader.cpp + source/external/cjson/cJSON.cpp + source/external/tinyxml2/tinyxml2.cpp + source/http/HttpClient.cpp + source/http/HttpClientFactory.cpp + source/http/HttpRequest.cpp + source/http/HttpTypes.cpp + source/http/Scheme.cpp + source/http/URI.cpp + source/http/curl/CurlHandleContainer.cpp + source/http/curl/CurlHttpClient.cpp + source/http/standard/StandardHttpRequest.cpp + source/http/standard/StandardHttpResponse.cpp + source/internal/AWSHttpResourceClient.cpp + source/monitoring/DefaultMonitoring.cpp + source/monitoring/HttpClientMetrics.cpp + source/monitoring/MonitoringManager.cpp + source/net/linux-shared/Net.cpp + source/net/linux-shared/SimpleUDP.cpp + source/platform/linux-shared/Environment.cpp + source/platform/linux-shared/FileSystem.cpp + source/platform/linux-shared/OSVersionInfo.cpp + source/platform/linux-shared/Security.cpp + source/platform/linux-shared/Time.cpp + source/utils/ARN.cpp + source/utils/Array.cpp + source/utils/DNS.cpp + source/utils/DateTimeCommon.cpp + source/utils/Directory.cpp + source/utils/EnumParseOverflowContainer.cpp + source/utils/FileSystemUtils.cpp + source/utils/GetTheLights.cpp + source/utils/HashingUtils.cpp + source/utils/StringUtils.cpp + source/utils/TempFile.cpp + source/utils/UUID.cpp + source/utils/base64/Base64.cpp + source/utils/crypto/Cipher.cpp + source/utils/crypto/ContentCryptoMaterial.cpp + source/utils/crypto/ContentCryptoScheme.cpp + source/utils/crypto/CryptoBuf.cpp + source/utils/crypto/CryptoStream.cpp + source/utils/crypto/EncryptionMaterials.cpp + source/utils/crypto/KeyWrapAlgorithm.cpp + source/utils/crypto/MD5.cpp + source/utils/crypto/Sha256.cpp + source/utils/crypto/Sha256HMAC.cpp + source/utils/crypto/factory/Factories.cpp + source/utils/crypto/openssl/CryptoImpl.cpp + source/utils/event/EventDecoderStream.cpp + source/utils/event/EventEncoderStream.cpp + source/utils/event/EventHeader.cpp + source/utils/event/EventMessage.cpp + source/utils/event/EventStreamBuf.cpp + source/utils/event/EventStreamDecoder.cpp + source/utils/event/EventStreamEncoder.cpp + source/utils/event/EventStreamErrors.cpp + source/utils/json/JsonSerializer.cpp + source/utils/logging/AWSLogging.cpp + source/utils/logging/ConsoleLogSystem.cpp + source/utils/logging/DefaultLogSystem.cpp + source/utils/logging/FormattedLogSystem.cpp + source/utils/logging/LogLevel.cpp + source/utils/memory/AWSMemory.cpp + source/utils/memory/stl/SimpleStringStream.cpp + source/utils/stream/ConcurrentStreamBuf.cpp + source/utils/stream/PreallocatedStreamBuf.cpp + source/utils/stream/ResponseStream.cpp + source/utils/stream/SimpleStreamBuf.cpp + source/utils/threading/Executor.cpp + source/utils/threading/ReaderWriterLock.cpp + source/utils/threading/Semaphore.cpp + source/utils/threading/ThreadTask.cpp + source/utils/xml/XmlSerializer.cpp +) + +END() |