| 1 | /* |
| 2 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"). |
| 5 | * You may not use this file except in compliance with the License. |
| 6 | * A copy of the License is located at |
| 7 | * |
| 8 | * http://aws.amazon.com/apache2.0 |
| 9 | * |
| 10 | * or in the "license" file accompanying this file. This file is distributed |
| 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
| 12 | * express or implied. See the License for the specific language governing |
| 13 | * permissions and limitations under the License. |
| 14 | */ |
| 15 | |
| 16 | #include <aws/core/utils/event/EventHeader.h> |
| 17 | #include <aws/core/utils/event/EventMessage.h> |
| 18 | #include <aws/core/utils/event/EventStreamEncoder.h> |
| 19 | #include <aws/core/utils/logging/LogMacros.h> |
| 20 | #include <aws/core/auth/AWSAuthSigner.h> |
| 21 | #include <aws/common/byte_order.h> |
| 22 | #include <aws/core/utils/memory/AWSMemory.h> |
| 23 | |
| 24 | #include <cassert> |
| 25 | |
| 26 | namespace Aws |
| 27 | { |
| 28 | namespace Utils |
| 29 | { |
| 30 | namespace Event |
| 31 | { |
| 32 | static const char TAG[] = "EventStreamEncoder" ; |
| 33 | |
| 34 | static void (const Aws::Utils::Event::Message& msg, aws_array_list* ) |
| 35 | { |
| 36 | aws_array_list_init_dynamic(headers, get_aws_allocator(), msg.GetEventHeaders().size(), sizeof(aws_event_stream_header_value_pair)); |
| 37 | for (auto&& : msg.GetEventHeaders()) |
| 38 | { |
| 39 | const uint8_t = static_cast<uint8_t>(header.first.length()); |
| 40 | switch(header.second.GetType()) |
| 41 | { |
| 42 | case EventHeaderValue::EventHeaderType::BOOL_TRUE: |
| 43 | case EventHeaderValue::EventHeaderType::BOOL_FALSE: |
| 44 | aws_event_stream_add_bool_header(headers, header.first.c_str(), headerKeyLen, header.second.GetEventHeaderValueAsBoolean()); |
| 45 | break; |
| 46 | case EventHeaderValue::EventHeaderType::BYTE: |
| 47 | aws_event_stream_add_bool_header(headers, header.first.c_str(), headerKeyLen, header.second.GetEventHeaderValueAsByte()); |
| 48 | break; |
| 49 | case EventHeaderValue::EventHeaderType::INT16: |
| 50 | aws_event_stream_add_int16_header(headers, header.first.c_str(), headerKeyLen, header.second.GetEventHeaderValueAsInt16()); |
| 51 | break; |
| 52 | case EventHeaderValue::EventHeaderType::INT32: |
| 53 | aws_event_stream_add_int32_header(headers, header.first.c_str(), headerKeyLen, header.second.GetEventHeaderValueAsInt32()); |
| 54 | break; |
| 55 | case EventHeaderValue::EventHeaderType::INT64: |
| 56 | aws_event_stream_add_int64_header(headers, header.first.c_str(), headerKeyLen, header.second.GetEventHeaderValueAsInt64()); |
| 57 | break; |
| 58 | case EventHeaderValue::EventHeaderType::BYTE_BUF: |
| 59 | { |
| 60 | const auto& bytes = header.second.GetEventHeaderValueAsBytebuf(); |
| 61 | aws_event_stream_add_bytebuf_header(headers, header.first.c_str(), headerKeyLen, bytes.GetUnderlyingData(), static_cast<uint16_t>(bytes.GetLength()), 1 /*copy*/); |
| 62 | } |
| 63 | break; |
| 64 | case EventHeaderValue::EventHeaderType::STRING: |
| 65 | { |
| 66 | const auto& bytes = header.second.GetUnderlyingBuffer(); |
| 67 | 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*/); |
| 68 | } |
| 69 | break; |
| 70 | case EventHeaderValue::EventHeaderType::TIMESTAMP: |
| 71 | aws_event_stream_add_timestamp_header(headers, header.first.c_str(), headerKeyLen, header.second.GetEventHeaderValueAsTimestamp()); |
| 72 | break; |
| 73 | case EventHeaderValue::EventHeaderType::UUID: |
| 74 | { |
| 75 | ByteBuffer uuidBytes = header.second.GetEventHeaderValueAsUuid(); |
| 76 | aws_event_stream_add_uuid_header(headers, header.first.c_str(), headerKeyLen, uuidBytes.GetUnderlyingData()); |
| 77 | } |
| 78 | break; |
| 79 | default: |
| 80 | AWS_LOG_ERROR(TAG, "Encountered unknown type of header." ); |
| 81 | break; |
| 82 | } |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | EventStreamEncoder::EventStreamEncoder(Client::AWSAuthSigner* signer) : m_signer(signer) |
| 87 | { |
| 88 | } |
| 89 | |
| 90 | |
| 91 | Aws::Vector<unsigned char> EventStreamEncoder::EncodeAndSign(const Aws::Utils::Event::Message& msg) |
| 92 | { |
| 93 | aws_event_stream_message encoded = Encode(msg); |
| 94 | aws_event_stream_message signedMessage = Sign(&encoded); |
| 95 | |
| 96 | const auto signedMessageLength = signedMessage.message_buffer ? aws_event_stream_message_total_length(&signedMessage) : 0; |
| 97 | |
| 98 | Aws::Vector<unsigned char> outputBits(signedMessage.message_buffer, signedMessage.message_buffer + signedMessageLength); |
| 99 | aws_event_stream_message_clean_up(&encoded); |
| 100 | aws_event_stream_message_clean_up(&signedMessage); |
| 101 | return outputBits; |
| 102 | } |
| 103 | |
| 104 | aws_event_stream_message EventStreamEncoder::Encode(const Aws::Utils::Event::Message& msg) |
| 105 | { |
| 106 | aws_array_list ; |
| 107 | EncodeHeaders(msg, &headers); |
| 108 | |
| 109 | aws_byte_buf payload; |
| 110 | payload.len = msg.GetEventPayload().size(); |
| 111 | // this const_cast is OK because aws_byte_buf will only be "read from" by the following functions. |
| 112 | payload.buffer = const_cast<uint8_t*>(msg.GetEventPayload().data()); |
| 113 | payload.capacity = 0; |
| 114 | payload.allocator = nullptr; |
| 115 | |
| 116 | aws_event_stream_message encoded; |
| 117 | if(aws_event_stream_message_init(&encoded, get_aws_allocator(), &headers, &payload) == AWS_OP_ERR) |
| 118 | { |
| 119 | AWS_LOGSTREAM_ERROR(TAG, "Error creating event-stream message from paylaod." ); |
| 120 | aws_event_stream_headers_list_cleanup(&headers); |
| 121 | // GCC 4.9.4 issues a warning with -Wextra if we simply do |
| 122 | // return {}; |
| 123 | aws_event_stream_message empty{nullptr, nullptr, 0}; |
| 124 | return empty; |
| 125 | } |
| 126 | aws_event_stream_headers_list_cleanup(&headers); |
| 127 | return encoded; |
| 128 | } |
| 129 | |
| 130 | aws_event_stream_message EventStreamEncoder::Sign(aws_event_stream_message* msg) |
| 131 | { |
| 132 | const auto msglen = msg->message_buffer ? aws_event_stream_message_total_length(msg) : 0; |
| 133 | Event::Message signedMessage; |
| 134 | signedMessage.WriteEventPayload(msg->message_buffer, msglen); |
| 135 | |
| 136 | assert(m_signer); |
| 137 | if (!m_signer->SignEventMessage(signedMessage, m_signatureSeed)) |
| 138 | { |
| 139 | AWS_LOGSTREAM_ERROR(TAG, "Failed to sign event message frame." ); |
| 140 | // GCC 4.9.4 issues a warning with -Wextra if we simply do |
| 141 | // return {}; |
| 142 | aws_event_stream_message empty{nullptr, nullptr, 0}; |
| 143 | return empty; |
| 144 | } |
| 145 | |
| 146 | aws_array_list ; |
| 147 | EncodeHeaders(signedMessage, &headers); |
| 148 | |
| 149 | aws_byte_buf payload; |
| 150 | payload.len = signedMessage.GetEventPayload().size(); |
| 151 | payload.buffer = signedMessage.GetEventPayload().data(); |
| 152 | payload.capacity = 0; |
| 153 | payload.allocator = nullptr; |
| 154 | |
| 155 | aws_event_stream_message signedmsg; |
| 156 | if(aws_event_stream_message_init(&signedmsg, get_aws_allocator(), &headers, &payload)) |
| 157 | { |
| 158 | AWS_LOGSTREAM_ERROR(TAG, "Error creating event-stream message from paylaod." ); |
| 159 | aws_event_stream_headers_list_cleanup(&headers); |
| 160 | // GCC 4.9.4 issues a warning with -Wextra if we simply do |
| 161 | // return {}; |
| 162 | aws_event_stream_message empty{nullptr, nullptr, 0}; |
| 163 | return empty; |
| 164 | } |
| 165 | aws_event_stream_headers_list_cleanup(&headers); |
| 166 | return signedmsg; |
| 167 | } |
| 168 | |
| 169 | } // namespace Event |
| 170 | } // namespace Utils |
| 171 | } // namespace Aws |
| 172 | |
| 173 | |