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 | |