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
23using namespace Aws::S3::Model;
24using namespace Aws::Utils::Event;
25using namespace Aws::Utils::Xml;
26
27namespace Aws
28{
29namespace S3
30{
31namespace 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& headers = GetEventHeaders();
84 auto messageTypeHeaderIter = 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& headers = GetEventHeaders();
112 auto eventTypeHeaderIter = 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& headers = GetEventHeaders();
170 Aws::String errorCode;
171 Aws::String errorMessage;
172 auto errorHeaderIter = 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
228namespace 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