63constexpr auto kContentTypeValue =
"application/x-amz-json-1.0";
64constexpr auto kAmzSdkRequestValue =
"attempt=1";
65constexpr auto kXAmzAPIVersionValue =
"2012-11-05";
66constexpr auto kAuthorizationOverrideDate =
"20150830T123600Z";
67constexpr auto kServiceName =
"sqs";
69constexpr http::headers::PredefinedHeader kAmzSdkRequestHeader{
"amz-sdk-request"};
70constexpr http::headers::PredefinedHeader kXAmzAPIVersionHeader{
"x-amz-api-version"};
71constexpr http::headers::PredefinedHeader kXYaCloudSubjectTokenHeader{
"X-YaCloud-SubjectToken"};
72constexpr http::headers::PredefinedHeader kAmzSdkInvocationIdHeader{
"amz-sdk-invocation-id"};
73constexpr http::headers::PredefinedHeader kXAmzDateHeader{
"x-amz-date"};
74constexpr http::headers::PredefinedHeader kXAmzSecurityTokenHeader{
"x-amz-security-token"};
75constexpr http::headers::PredefinedHeader kXAmzTargetHeader{
"x-amz-target"};
76constexpr http::headers::PredefinedHeader kXAmznQueryModeHeader{
"x-amzn-query-mode"};
78constexpr utils::
StringLiteral kTracingTypeRequest =
"request";
81constexpr utils::
StringLiteral kTracingRequestBodyLength =
"request_body_length";
83constexpr std::string_view kMaskedHeaderValue =
"***";
85bool IsSensitiveHeader(std::string_view header_name) {
86 const auto lower = utils::text::ToLower(header_name);
87 return lower ==
"authorization" || lower ==
"x-yacloud-subjecttoken" || lower ==
"x-amz-security-token";
90std::string FormatRequestHeaders(
const clients::http::Headers& headers) {
91 std::vector<std::pair<std::string_view, std::string_view>> sorted_headers;
92 sorted_headers.reserve(headers.size());
93 for (
const auto& [name, value] : headers) {
94 sorted_headers.emplace_back(name, value);
96 std::ranges::sort(sorted_headers, [](
const auto& lhs,
const auto& rhs) {
return lhs.first < rhs.first; });
99 for (
const auto& [name, value] : sorted_headers) {
102 result.append(IsSensitiveHeader(name) ? kMaskedHeaderValue : value);
103 result.push_back(
'\n');
109 const char* operation_name,
110 std::string_view url,
111 const clients::http::Headers& headers,
112 std::string_view body
115 logging::LogExtra log_extra{
116 {tracing::kHttpMetaType, operation_name},
117 {tracing::kType, kTracingTypeRequest},
118 {kTracingRequestBodyLength,
static_cast<
unsigned long long>(body.size())},
119 {kTracingBody, body},
121 {tracing::kHttpMethod, kHttpMethodPost},
123 log_extra.Extend(
"request_headers", FormatRequestHeaders(headers));
124 logger.Format(
"start SQS {} {}", kHttpMethodPost, operation_name) << log_extra;
131std::string MakeHostHeaderValue(std::string_view url) {
132 const auto host = http::ExtractHostnameView(url);
133 const auto after_host =
static_cast<std::size_t>(host.data() + host.size() - url.data());
134 if (after_host >= url.size() || url[after_host] !=
':') {
135 return std::string{host};
138 auto port = url.substr(after_host);
139 const auto port_end = port.find_first_of(
"/?#");
140 if (port_end != std::string_view::npos) {
141 port = port.substr(0, port_end);
145 result.reserve(host.size() + port.size());
151std::string CanonicalUri(std::string_view url) {
152 auto path = http::ExtractPathView(url);
156 return http::EncodeS3Key(path);
159std::string EncodeBinary(
const Aws::Utils::ByteBuffer& buffer) {
160 return crypto::base64::Base64Encode(std::string_view{
161 reinterpret_cast<
const char*>(buffer.GetUnderlyingData()),
166Aws::Utils::ByteBuffer DecodeBinary(
const Aws::String& value) {
167 const auto decoded = crypto::base64::Base64Decode(std::string_view{value.c_str(), value.size()});
168 return Aws::Utils::ByteBuffer{
reinterpret_cast<
const unsigned char*>(decoded.data()), decoded.size()};
172Aws::Utils::Json::JsonValue BuildAttributeValueJson(
const T& attr_value) {
173 Aws::Utils::Json::JsonValue attr_value_json;
174 attr_value_json.WithString(
"DataType", attr_value.GetDataType());
176 if (attr_value.StringValueHasBeenSet()) {
177 attr_value_json.WithString(
"StringValue", attr_value.GetStringValue());
180 if (attr_value.StringListValuesHasBeenSet()) {
181 Aws::Vector<Aws::Utils::Json::JsonValue> string_list_values_vector;
182 string_list_values_vector.reserve(attr_value.GetStringListValues().size());
183 for (
const auto& string_value : attr_value.GetStringListValues()) {
184 Aws::Utils::Json::JsonValue string_value_json;
185 string_value_json.AsString(string_value);
186 string_list_values_vector.push_back(string_value_json);
188 Aws::Utils::Array<Aws::Utils::Json::JsonValue> string_list_values_array(string_list_values_vector.size());
189 for (size_t i = 0; i < string_list_values_vector.size(); ++i) {
190 string_list_values_array[i] = string_list_values_vector[i];
192 attr_value_json.WithArray(
"StringListValues", string_list_values_array);
195 if (attr_value.BinaryValueHasBeenSet()) {
196 const auto& binary_value = attr_value.GetBinaryValue();
197 attr_value_json.WithString(
"BinaryValue", Aws::String{EncodeBinary(binary_value)});
200 if (attr_value.BinaryListValuesHasBeenSet()) {
201 Aws::Vector<Aws::Utils::Json::JsonValue> binary_list_values_vector;
202 binary_list_values_vector.reserve(attr_value.GetBinaryListValues().size());
203 for (
const auto& binary_value : attr_value.GetBinaryListValues()) {
204 const auto encoded = EncodeBinary(binary_value);
205 Aws::Utils::Json::JsonValue binary_value_json;
206 binary_value_json.AsString(Aws::String{encoded});
207 binary_list_values_vector.push_back(binary_value_json);
209 Aws::Utils::Array<Aws::Utils::Json::JsonValue> binary_list_values_array(binary_list_values_vector.size());
210 for (size_t i = 0; i < binary_list_values_vector.size(); ++i) {
211 binary_list_values_array[i] = binary_list_values_vector[i];
213 attr_value_json.WithArray(
"BinaryListValues", binary_list_values_array);
216 return attr_value_json;
219Aws::Utils::Json::JsonValue BuildMessageAttributesJson(
220 const Aws::Map<Aws::String, MessageAttributeValue>& message_attributes
222 Aws::Utils::Json::JsonValue message_attributes_json;
223 for (
const auto& attr_pair : message_attributes) {
224 message_attributes_json.WithObject(attr_pair.first, BuildAttributeValueJson(attr_pair.second));
226 return message_attributes_json;
229Aws::Utils::Json::JsonValue BuildMessageSystemAttributesJson(
230 const Aws::Map<MessageSystemAttributeNameForSends, MessageSystemAttributeValue>& message_system_attributes
232 Aws::Utils::Json::JsonValue message_system_attributes_json;
233 for (
const auto& attr_pair : message_system_attributes) {
234 Aws::String attr_name =
235 MessageSystemAttributeNameForSendsMapper::GetNameForMessageSystemAttributeNameForSends(attr_pair.first);
236 message_system_attributes_json.WithObject(attr_name, BuildAttributeValueJson(attr_pair.second));
238 return message_system_attributes_json;
241Aws::Utils::Json::JsonValue BuildQueueAttributesJson(
const Aws::Map<QueueAttributeName, Aws::String>& attributes) {
242 Aws::Utils::Json::JsonValue attributes_json;
243 for (
const auto& attr_pair : attributes) {
245 .WithString(QueueAttributeNameMapper::GetNameForQueueAttributeName(attr_pair.first), attr_pair.second);
247 return attributes_json;
250Aws::Utils::Json::JsonValue BuildTagsJson(
const Aws::Map<Aws::String, Aws::String>& tags) {
251 Aws::Utils::Json::JsonValue tags_json;
252 for (
const auto& tag_pair : tags) {
253 tags_json.WithString(tag_pair.first, tag_pair.second);
258template <
typename Container>
259Aws::Utils::Array<Aws::Utils::Json::JsonValue> BuildStringArrayJson(
const Container& strings) {
260 Aws::Utils::Array<Aws::Utils::Json::JsonValue> array(strings.size());
261 for (size_t i = 0; i < strings.size(); ++i) {
262 array[i].AsString(strings[i]);
267Aws::String JsonViewToString(
const Aws::Utils::Json::JsonView& value_view) {
268 if (value_view.IsString()) {
269 return value_view.AsString();
271 if (value_view.IsIntegerType()) {
272 return Aws::Utils::StringUtils::to_string(value_view.AsInteger());
274 if (value_view.IsFloatingPointType()) {
275 return Aws::Utils::StringUtils::to_string(value_view.AsDouble());
277 if (value_view.IsBool()) {
278 return value_view.AsBool() ?
"true" :
"false";
283bool JsonViewIsScalar(
const Aws::Utils::Json::JsonView& value_view) {
284 return value_view.IsString() || value_view.IsIntegerType() || value_view.IsFloatingPointType() ||
288Aws::String ExtractErrorMessage(
const Aws::Utils::Json::JsonView& error_view) {
289 Aws::Vector<Aws::String> parts;
291 if (error_view.KeyExists(
"Code")) {
292 parts.push_back(error_view.GetString(
"Code"));
294 if (error_view.KeyExists(
"__type")) {
295 parts.push_back(error_view.GetString(
"__type"));
297 if (error_view.KeyExists(
"Message")) {
298 parts.push_back(error_view.GetString(
"Message"));
300 if (error_view.KeyExists(
"message")) {
301 parts.push_back(error_view.GetString(
"message"));
308 Aws::String result = parts.front();
309 for (size_t i = 1; i < parts.size(); ++i) {
316Aws::String ExtractErrorMessageFromBody(utils::zstring_view body_string) {
317 if (body_string.empty()) {
321 Aws::Utils::Json::JsonValue response_json(Aws::String{body_string.c_str(), body_string.size()});
322 if (!response_json.WasParseSuccessful()) {
323 return Aws::String{body_string.c_str(), body_string.size()};
326 auto response_view = response_json.View();
327 if (response_view.KeyExists(
"Error") && response_view.GetObject(
"Error").IsObject()) {
328 const auto error_message = ExtractErrorMessage(response_view.GetObject(
"Error"));
329 if (!error_message.empty()) {
330 return error_message;
334 return ExtractErrorMessage(response_view);
337Aws::Map<QueueAttributeName, Aws::String> ParseQueueAttributesJson(
const Aws::Utils::Json::JsonView& attributes_view) {
338 Aws::Map<QueueAttributeName, Aws::String> attributes;
339 for (
const auto& [attribute_name, attribute_value] : attributes_view.GetAllObjects()) {
340 if (JsonViewIsScalar(attribute_value)) {
341 attributes[QueueAttributeNameMapper::GetQueueAttributeNameForName(attribute_name
342 )] = JsonViewToString(attribute_value);
348Aws::Map<Aws::String, Aws::String> ParseTagsJson(
const Aws::Utils::Json::JsonView& tags_view) {
349 Aws::Map<Aws::String, Aws::String> tags;
350 for (
const auto& [tag_key, tag_value] : tags_view.GetAllObjects()) {
351 if (tag_value.IsString()) {
352 tags[tag_key] = tag_value.AsString();
358Message ParseMessageJson(
const Aws::Utils::Json::JsonView& message_view) {
360 message.WithBody(message_view.GetString(
"Body"))
361 .WithMessageId(message_view.GetString(
"MessageId"))
362 .WithReceiptHandle(message_view.GetString(
"ReceiptHandle"))
363 .WithMD5OfBody(message_view.GetString(
"MD5OfBody"));
365 if (message_view.KeyExists(
"MD5OfMessageAttributes")) {
366 message.WithMD5OfMessageAttributes(message_view.GetString(
"MD5OfMessageAttributes"));
369 if (message_view.KeyExists(
"Attributes")) {
370 const auto& message_attributes = message_view.GetObject(
"Attributes");
371 Aws::Map<MessageSystemAttributeName, Aws::String> message_system_attributes_map;
372 for (
const auto& [attribute_name, attribute_value] : message_attributes.GetAllObjects()) {
373 auto message_attribute =
374 MessageSystemAttributeNameMapper::GetMessageSystemAttributeNameForName(attribute_name);
375 if (JsonViewIsScalar(attribute_value)) {
376 message_system_attributes_map[message_attribute] = JsonViewToString(attribute_value);
379 message.WithAttributes(message_system_attributes_map);
382 if (message_view.KeyExists(
"MessageAttributes")) {
383 const auto& message_attributes = message_view.GetObject(
"MessageAttributes");
384 Aws::Map<Aws::String, MessageAttributeValue> message_attributes_map;
385 for (
const auto& [attribute_name, attribute_value] : message_attributes.GetAllObjects()) {
386 if (attribute_value.IsObject()) {
387 const auto attr_object = attribute_value.AsObject();
388 MessageAttributeValue attr;
389 if (attr_object.KeyExists(
"DataType")) {
390 attr.WithDataType(attr_object.GetString(
"DataType"));
392 if (attr_object.KeyExists(
"StringValue")) {
393 attr.WithStringValue(attr_object.GetString(
"StringValue"));
395 if (attr_object.KeyExists(
"BinaryValue")) {
396 attr.WithBinaryValue(DecodeBinary(attr_object.GetString(
"BinaryValue")));
398 if (attr_object.KeyExists(
"StringListValues")) {
399 const auto string_list_values = attr_object.GetArray(
"StringListValues");
400 for (size_t i = 0; i < string_list_values.GetLength(); ++i) {
401 attr.AddStringListValues(string_list_values[i].AsString());
404 if (attr_object.KeyExists(
"BinaryListValues")) {
405 const auto binary_list_values = attr_object.GetArray(
"BinaryListValues");
406 for (size_t i = 0; i < binary_list_values.GetLength(); ++i) {
407 attr.AddBinaryListValues(DecodeBinary(binary_list_values[i].AsString()));
410 message_attributes_map[attribute_name] = attr;
413 message.WithMessageAttributes(message_attributes_map);
419template <
typename Outcome>
420Outcome MakeHttpErrorOutcome(
int status_code, utils::
zstring_view body, Aws::String message = {}) {
421 Aws::SQS::SQSError error;
422 error.SetResponseCode(
static_cast<Aws::Http::HttpResponseCode>(status_code));
423 if (message.empty()) {
424 message = ExtractErrorMessageFromBody(body);
426 if (!message.empty()) {
427 error.SetMessage(message);
429 return Outcome(error);
432template <
typename Outcome>
433Outcome MakeJsonParseErrorOutcome(
const impl::JsonResponse& response) {
434 return MakeHttpErrorOutcome<Outcome>(response.status_code, response.body, response.json.GetErrorMessage());
437template <
typename Outcome>
438Outcome MakeFailedOutcome(
const impl::JsonResponse& response) {
439 if (!response.transport_error.empty()) {
440 return MakeHttpErrorOutcome<Outcome>(
441 response.status_code,
443 Aws::String{response.transport_error.c_str(), response.transport_error.size()}
446 if (response.status_code != 200) {
447 return MakeHttpErrorOutcome<Outcome>(response.status_code, response.body);
449 return MakeJsonParseErrorOutcome<Outcome>(response);
454class JsonClient::Impl {
473 "sqs::ClientSettings.timeout must be positive"
477 "sqs::ClientSettings.region is empty; set the AWS signing region "
478 "(for example, ru-central1 or us-east-1)"
633 "ChangeMessageVisibility",
663 "ChangeMessageVisibilityBatch",
755 "DeleteMessageBatch",
813 "GetQueueAttributes",
870 "ListDeadLetterSourceQueues",
1056 "MessageSystemAttributes",
1111 "MessageSystemAttributes",
1177 "SetQueueAttributes",