1 | /* |
2 | * Copyright 2010-2017 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/s3/model/SelectObjectContentHandler.h> |
17 | #include <aws/s3/S3ErrorMarshaller.h> |
18 | #include <aws/core/client/CoreErrors.h> |
19 | #include <aws/core/utils/event/EventStreamErrors.h> |
20 | #include <aws/core/utils/logging/LogMacros.h> |
21 | #include <aws/core/utils/xml/XmlSerializer.h> |
22 | |
23 | using namespace Aws::S3::Model; |
24 | using namespace Aws::Utils::Event; |
25 | using namespace Aws::Utils::Xml; |
26 | |
27 | namespace Aws |
28 | { |
29 | namespace S3 |
30 | { |
31 | namespace Model |
32 | { |
33 | using namespace Aws::Client; |
34 | |
35 | static const char SELECTOBJECTCONTENT_HANDLER_CLASS_TAG[] = "SelectObjectContentHandler" ; |
36 | |
37 | SelectObjectContentHandler::SelectObjectContentHandler() : EventStreamHandler() |
38 | { |
39 | m_onRecordsEvent = [&](const RecordsEvent&) |
40 | { |
41 | AWS_LOGSTREAM_TRACE(SELECTOBJECTCONTENT_HANDLER_CLASS_TAG, "RecordsEvent received." ); |
42 | }; |
43 | |
44 | m_onStatsEvent = [&](const StatsEvent&) |
45 | { |
46 | AWS_LOGSTREAM_TRACE(SELECTOBJECTCONTENT_HANDLER_CLASS_TAG, "StatsEvent received." ); |
47 | }; |
48 | |
49 | m_onProgressEvent = [&](const ProgressEvent&) |
50 | { |
51 | AWS_LOGSTREAM_TRACE(SELECTOBJECTCONTENT_HANDLER_CLASS_TAG, "ProgressEvent received." ); |
52 | }; |
53 | |
54 | m_onContinuationEvent = [&]() |
55 | { |
56 | AWS_LOGSTREAM_TRACE(SELECTOBJECTCONTENT_HANDLER_CLASS_TAG, "ContinuationEvent received." ); |
57 | }; |
58 | |
59 | m_onEndEvent = [&]() |
60 | { |
61 | AWS_LOGSTREAM_TRACE(SELECTOBJECTCONTENT_HANDLER_CLASS_TAG, "EndEvent received." ); |
62 | }; |
63 | |
64 | m_onError = [&](const AWSError<S3Errors>& error) |
65 | { |
66 | AWS_LOGSTREAM_TRACE(SELECTOBJECTCONTENT_HANDLER_CLASS_TAG, "S3 Errors received, " << error); |
67 | }; |
68 | } |
69 | |
70 | void SelectObjectContentHandler::OnEvent() |
71 | { |
72 | using namespace Aws::Utils::Event; |
73 | |
74 | // Handler internal error during event stream decoding. |
75 | if (!*this) |
76 | { |
77 | AWSError<CoreErrors> error = EventStreamErrorsMapper::GetAwsErrorForEventStreamError(GetInternalError()); |
78 | error.SetMessage(GetEventPayloadAsString()); |
79 | m_onError(AWSError<S3Errors>(error)); |
80 | return; |
81 | } |
82 | |
83 | const auto& = GetEventHeaders(); |
84 | auto = headers.find(MESSAGE_TYPE_HEADER); |
85 | if (messageTypeHeaderIter == headers.end()) |
86 | { |
87 | AWS_LOGSTREAM_WARN(SELECTOBJECTCONTENT_HANDLER_CLASS_TAG, "Header: " << MESSAGE_TYPE_HEADER << " not found in the message." ); |
88 | return; |
89 | } |
90 | |
91 | switch (Message::GetMessageTypeForName(messageTypeHeaderIter->second.GetEventHeaderValueAsString())) |
92 | { |
93 | case Message::MessageType::EVENT: |
94 | HandleEventInMessage(); |
95 | break; |
96 | case Message::MessageType::REQUEST_LEVEL_ERROR: |
97 | case Message::MessageType::REQUEST_LEVEL_EXCEPTION: |
98 | { |
99 | HandleErrorInMessage(); |
100 | break; |
101 | } |
102 | default: |
103 | AWS_LOGSTREAM_WARN(SELECTOBJECTCONTENT_HANDLER_CLASS_TAG, |
104 | "Unexpected message type: " << messageTypeHeaderIter->second.GetEventHeaderValueAsString()); |
105 | break; |
106 | } |
107 | } |
108 | |
109 | void SelectObjectContentHandler::HandleEventInMessage() |
110 | { |
111 | const auto& = GetEventHeaders(); |
112 | auto = headers.find(EVENT_TYPE_HEADER); |
113 | if (eventTypeHeaderIter == headers.end()) |
114 | { |
115 | AWS_LOGSTREAM_WARN(SELECTOBJECTCONTENT_HANDLER_CLASS_TAG, "Header: " << EVENT_TYPE_HEADER << " not found in the message." ); |
116 | return; |
117 | } |
118 | switch (SelectObjectContentEventMapper::GetSelectObjectContentEventTypeForName(eventTypeHeaderIter->second.GetEventHeaderValueAsString())) |
119 | { |
120 | case SelectObjectContentEventType::RECORDS: |
121 | { |
122 | RecordsEvent event(GetEventPayloadWithOwnership()); |
123 | m_onRecordsEvent(event); |
124 | break; |
125 | } |
126 | case SelectObjectContentEventType::STATS: |
127 | { |
128 | auto xmlDoc = XmlDocument::CreateFromXmlString(GetEventPayloadAsString()); |
129 | if (!xmlDoc.WasParseSuccessful()) |
130 | { |
131 | AWS_LOGSTREAM_WARN(SELECTOBJECTCONTENT_HANDLER_CLASS_TAG, "Unable to generate a proper StatsEvent object from the response in XML format." ); |
132 | break; |
133 | } |
134 | |
135 | m_onStatsEvent(StatsEvent(xmlDoc.GetRootElement())); |
136 | break; |
137 | } |
138 | case SelectObjectContentEventType::PROGRESS: |
139 | { |
140 | auto xmlDoc = XmlDocument::CreateFromXmlString(GetEventPayloadAsString()); |
141 | if (!xmlDoc.WasParseSuccessful()) |
142 | { |
143 | AWS_LOGSTREAM_WARN(SELECTOBJECTCONTENT_HANDLER_CLASS_TAG, "Unable to generate a proper ProgressEvent object from the response in XML format." ); |
144 | break; |
145 | } |
146 | |
147 | m_onProgressEvent(ProgressEvent(xmlDoc.GetRootElement())); |
148 | break; |
149 | } |
150 | case SelectObjectContentEventType::CONT: |
151 | { |
152 | m_onContinuationEvent(); |
153 | break; |
154 | } |
155 | case SelectObjectContentEventType::END: |
156 | { |
157 | m_onEndEvent(); |
158 | break; |
159 | } |
160 | default: |
161 | AWS_LOGSTREAM_WARN(SELECTOBJECTCONTENT_HANDLER_CLASS_TAG, |
162 | "Unexpected event type: " << eventTypeHeaderIter->second.GetEventHeaderValueAsString()); |
163 | break; |
164 | } |
165 | } |
166 | |
167 | void SelectObjectContentHandler::HandleErrorInMessage() |
168 | { |
169 | const auto& = GetEventHeaders(); |
170 | Aws::String errorCode; |
171 | Aws::String errorMessage; |
172 | auto = headers.find(ERROR_CODE_HEADER); |
173 | if (errorHeaderIter == headers.end()) |
174 | { |
175 | errorHeaderIter = headers.find(EXCEPTION_TYPE_HEADER); |
176 | if (errorHeaderIter == headers.end()) |
177 | { |
178 | AWS_LOGSTREAM_WARN(SELECTOBJECTCONTENT_HANDLER_CLASS_TAG, |
179 | "Error type was not found in the event message." ); |
180 | return; |
181 | } |
182 | } |
183 | |
184 | errorCode = errorHeaderIter->second.GetEventHeaderValueAsString(); |
185 | errorHeaderIter = headers.find(ERROR_MESSAGE_HEADER); |
186 | if (errorHeaderIter == headers.end()) |
187 | { |
188 | errorHeaderIter = headers.find(EXCEPTION_TYPE_HEADER); |
189 | if (errorHeaderIter == headers.end()) |
190 | { |
191 | AWS_LOGSTREAM_WARN(SELECTOBJECTCONTENT_HANDLER_CLASS_TAG, |
192 | "Error description was not found in the event message." ); |
193 | return; |
194 | } |
195 | } |
196 | errorMessage = errorHeaderIter->second.GetEventHeaderValueAsString(); |
197 | MarshallError(errorCode, errorMessage); |
198 | } |
199 | |
200 | void SelectObjectContentHandler::MarshallError(const Aws::String& errorCode, const Aws::String& errorMessage) |
201 | { |
202 | S3ErrorMarshaller errorMarshaller; |
203 | AWSError<CoreErrors> error; |
204 | |
205 | if (errorCode.empty()) |
206 | { |
207 | error = AWSError<CoreErrors>(CoreErrors::UNKNOWN, "" , errorMessage, false); |
208 | } |
209 | else |
210 | { |
211 | error = errorMarshaller.FindErrorByName(errorMessage.c_str()); |
212 | if (error.GetErrorType() != CoreErrors::UNKNOWN) |
213 | { |
214 | AWS_LOGSTREAM_WARN(SELECTOBJECTCONTENT_HANDLER_CLASS_TAG, "Encountered AWSError '" << errorCode.c_str() << "': " << errorMessage.c_str()); |
215 | error.SetExceptionName(errorCode); |
216 | error.SetMessage(errorMessage); |
217 | } |
218 | else |
219 | { |
220 | AWS_LOGSTREAM_WARN(SELECTOBJECTCONTENT_HANDLER_CLASS_TAG, "Encountered Unknown AWSError '" << errorCode.c_str() << "': " << errorMessage.c_str()); |
221 | error = AWSError<CoreErrors>(CoreErrors::UNKNOWN, errorCode, "Unable to parse ExceptionName: " + errorCode + " Message: " + errorMessage, false); |
222 | } |
223 | } |
224 | |
225 | m_onError(AWSError<S3Errors>(error)); |
226 | } |
227 | |
228 | namespace SelectObjectContentEventMapper |
229 | { |
230 | static const int RECORDS_HASH = Aws::Utils::HashingUtils::HashString("Records" ); |
231 | static const int STATS_HASH = Aws::Utils::HashingUtils::HashString("Stats" ); |
232 | static const int PROGRESS_HASH = Aws::Utils::HashingUtils::HashString("Progress" ); |
233 | static const int CONT_HASH = Aws::Utils::HashingUtils::HashString("Cont" ); |
234 | static const int END_HASH = Aws::Utils::HashingUtils::HashString("End" ); |
235 | |
236 | SelectObjectContentEventType GetSelectObjectContentEventTypeForName(const Aws::String& name) |
237 | { |
238 | int hashCode = Aws::Utils::HashingUtils::HashString(name.c_str()); |
239 | if (hashCode == RECORDS_HASH) |
240 | { |
241 | return SelectObjectContentEventType::RECORDS; |
242 | } |
243 | else if (hashCode == STATS_HASH) |
244 | { |
245 | return SelectObjectContentEventType::STATS; |
246 | } |
247 | else if (hashCode == PROGRESS_HASH) |
248 | { |
249 | return SelectObjectContentEventType::PROGRESS; |
250 | } |
251 | else if (hashCode == CONT_HASH) |
252 | { |
253 | return SelectObjectContentEventType::CONT; |
254 | } |
255 | else if (hashCode == END_HASH) |
256 | { |
257 | return SelectObjectContentEventType::END; |
258 | } |
259 | return SelectObjectContentEventType::UNKNOWN; |
260 | } |
261 | |
262 | Aws::String GetNameForSelectObjectContentEventType(SelectObjectContentEventType value) |
263 | { |
264 | switch (value) |
265 | { |
266 | case SelectObjectContentEventType::RECORDS: |
267 | return "Records" ; |
268 | case SelectObjectContentEventType::STATS: |
269 | return "Stats" ; |
270 | case SelectObjectContentEventType::PROGRESS: |
271 | return "Progress" ; |
272 | case SelectObjectContentEventType::CONT: |
273 | return "Cont" ; |
274 | case SelectObjectContentEventType::END: |
275 | return "End" ; |
276 | default: |
277 | return "Unknown" ; |
278 | } |
279 | } |
280 | } // namespace SelectObjectContentEventMapper |
281 | } // namespace Model |
282 | } // namespace S3 |
283 | } // namespace Aws |
284 | |