Kea 1.5.0
json_feed.cc
Go to the documentation of this file.
1// Copyright (C) 2017-2018 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <cc/data.h>
10#include <cc/json_feed.h>
11#include <boost/bind.hpp>
12
13using namespace isc::data;
14using namespace isc::util;
15
16namespace isc {
17namespace config {
18
25const int JSONFeed::JSON_END_ST;
26const int JSONFeed::FEED_OK_ST;
28
32const int JSONFeed::FEED_OK_EVT;
34
36 : StateModel(), buffer_(), data_ptr_(0), error_message_(), open_scopes_(0),
37 output_() {
38}
39
40void
42 // Initialize dictionaries of events and states.
44
45 // Set the current state to starting state and enter the run loop.
47
48 // Parsing starts from here.
50}
51
52void
54 try {
55 // Process the input data until no more data is available or until
56 // JSON feed ends with matching closing brace.
57 do {
58 getState(getCurrState())->run();
59
60 } while (!isModelDone() && (getNextEvent() != NOP_EVT) &&
62 } catch (const std::exception& ex) {
63 abortModel(ex.what());
64 }
65}
66
67bool
69 return ((getNextEvent() == NEED_MORE_DATA_EVT) ||
70 (getNextEvent() == START_EVT));
71}
72
73bool
75 return ((getNextEvent() == END_EVT) &&
77}
78
81 if (needData()) {
82 isc_throw(JSONFeedError, "unable to retrieve the data form the"
83 " JSON feed while parsing hasn't finished");
84 }
85 try {
86 return (Element::fromWire(output_));
87
88 } catch (const std::exception& ex) {
90 }
91}
92
93void
94JSONFeed::postBuffer(const void* buf, const size_t buf_size) {
95 if (buf_size > 0) {
96 // The next event is NEED_MORE_DATA_EVT when the parser wants to
97 // signal that more data is needed. This method is called to supply
98 // more data and thus it should change the next event to
99 // MORE_DATA_PROVIDED_EVT.
102 }
103 buffer_.assign(static_cast<const char*>(buf),
104 static_cast<const char*>(buf) + buf_size);
105 data_ptr_ = 0;
106 }
107}
108
109void
110JSONFeed::defineEvents() {
112
113 // Define JSONFeed specific events.
114 defineEvent(DATA_READ_OK_EVT, "DATA_READ_OK_EVT");
115 defineEvent(NEED_MORE_DATA_EVT, "NEED_MORE_DATA_EVT");
116 defineEvent(MORE_DATA_PROVIDED_EVT, "MORE_DATA_PROVIDED_EVT");
117 defineEvent(FEED_OK_EVT, "FEED_OK_EVT");
118 defineEvent(FEED_FAILED_EVT, "FEED_FAILED_EVT");
119}
120
121void
122JSONFeed::verifyEvents() {
124
130}
131
132void
133JSONFeed::defineStates() {
134 // Call parent class implementation first.
136
137 defineState(RECEIVE_START_ST, "RECEIVE_START_ST",
138 boost::bind(&JSONFeed::receiveStartHandler, this));
139 defineState(WHITESPACE_BEFORE_JSON_ST, "WHITESPACE_BEFORE_JSON_ST",
140 boost::bind(&JSONFeed::whiteSpaceBeforeJSONHandler, this));
141 defineState(INNER_JSON_ST, "INNER_JSON_ST",
142 boost::bind(&JSONFeed::innerJSONHandler, this));
143 defineState(STRING_JSON_ST, "STRING_JSON_ST",
144 boost::bind(&JSONFeed::stringJSONHandler, this));
145 defineState(ESCAPE_JSON_ST, "ESCAPE_JSON_ST",
146 boost::bind(&JSONFeed::escapeJSONHandler, this));
147 defineState(JSON_END_ST, "JSON_END_ST",
148 boost::bind(&JSONFeed::endJSONHandler, this));
149}
150
151void
152JSONFeed::feedFailure(const std::string& error_msg) {
153 error_message_ = error_msg;
155}
156
157void
158JSONFeed::onModelFailure(const std::string& explanation) {
159 if (error_message_.empty()) {
160 error_message_ = explanation;
161 }
162}
163
164bool
165JSONFeed::popNextFromBuffer(char& next) {
166 // If there are any characters in the buffer, pop next.
167 if (!buffer_.empty() && (data_ptr_ < buffer_.size())) {
168 next = buffer_[data_ptr_++];
169 return (true);
170 }
171 return (false);
172}
173
174char
175JSONFeed::getNextFromBuffer() {
176 unsigned int ev = getNextEvent();
177 char c = '\0';
178 // The caller should always provide additional data when the
179 // NEED_MORE_DATA_EVT occurs. If the next event is still
180 // NEED_MORE_DATA_EVT it indicates that the caller hasn't provided
181 // the data.
182 if (ev == NEED_MORE_DATA_EVT) {
183 isc_throw(JSONFeedError,
184 "JSONFeed requires new data to progress, but no data"
185 " have been provided. The transaction is aborted to avoid"
186 " a deadlock.");
187
188 } else {
189 // Try to pop next character from the buffer.
190 const bool data_exist = popNextFromBuffer(c);
191 if (!data_exist) {
192 // There is no more data so it is really not possible that we're
193 // at MORE_DATA_PROVIDED_EVT.
194 if (ev == MORE_DATA_PROVIDED_EVT) {
195 isc_throw(JSONFeedError,
196 "JSONFeed state indicates that new data have been"
197 " provided to be parsed, but the transaction buffer"
198 " contains no new data.");
199
200 } else {
201 // If there is no more data we should set NEED_MORE_DATA_EVT
202 // event to indicate that new data should be provided.
204 }
205 }
206 }
207 return (c);
208}
209
210void
211JSONFeed::invalidEventError(const std::string& handler_name,
212 const unsigned int event) {
213 isc_throw(JSONFeedError, handler_name << ": "
214 << " invalid event " << getEventLabel(static_cast<int>(event)));
215}
216
217void
218JSONFeed::receiveStartHandler() {
219 char c = getNextFromBuffer();
221 switch (getNextEvent()) {
222 case START_EVT:
223 switch (c) {
224 case '\t':
225 case '\n':
226 case '\r':
227 case ' ':
229 return;
230
231 case '{':
232 case '[':
233 output_.push_back(c);
234 ++open_scopes_;
236 return;
237
238 // Cannot start by a string
239 case '"':
240 default:
241 feedFailure("invalid first character " + std::string(1, c));
242 break;
243 }
244 break;
245
246 default:
247 invalidEventError("receiveStartHandler", getNextEvent());
248 }
249 }
250}
251
252void
253JSONFeed::whiteSpaceBeforeJSONHandler() {
254 char c = getNextFromBuffer();
256 switch (c) {
257 case '\t':
258 case '\n':
259 case '\r':
260 case ' ':
262 break;
263
264 case '{':
265 case '[':
266 output_.push_back(c);
267 ++open_scopes_;
269 break;
270
271 // Cannot start by a string
272 case '"':
273 default:
274 feedFailure("invalid character " + std::string(1, c));
275 }
276 }
277}
278
279void
280JSONFeed::innerJSONHandler() {
281 char c = getNextFromBuffer();
283 output_.push_back(c);
284
285 switch(c) {
286 case '{':
287 case '[':
289 ++open_scopes_;
290 break;
291
292 case '}':
293 case ']':
294 if (--open_scopes_ == 0) {
296
297 } else {
299 }
300 break;
301
302 case '"':
304 break;
305
306 default:
308 }
309 }
310}
311
312void
313JSONFeed::stringJSONHandler() {
314 char c = getNextFromBuffer();
316 output_.push_back(c);
317
318 switch(c) {
319 case '"':
321 break;
322
323 case '\\':
325 break;
326
327 default:
329 }
330 }
331}
332
333void
334JSONFeed::escapeJSONHandler() {
335 char c = getNextFromBuffer();
337 output_.push_back(c);
338
340 }
341}
342
343void
344JSONFeed::endJSONHandler() {
345 switch (getNextEvent()) {
346 case FEED_OK_EVT:
348 break;
349
350 case FEED_FAILED_EVT:
351 abortModel("reading into JSON feed failed");
352 break;
353
354 default:
355 invalidEventError("endJSONHandler", getNextEvent());
356 }
357}
358
359
360} // end of namespace config
361} // end of namespace isc
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception thrown upon an error in the JSONFeed.
Definition: json_feed.h:30
static const int ESCAPE_JSON_ST
JSON escape next character.
Definition: json_feed.h:91
static const int FEED_FAILED_ST
Invalid syntax detected.
Definition: json_feed.h:106
void postBuffer(const void *buf, const size_t buf_size)
Receives additional data read from a data stream.
Definition: json_feed.cc:94
static const int WHITESPACE_BEFORE_JSON_ST
Skipping whitespaces before actual JSON.
Definition: json_feed.h:79
bool feedOk() const
Checks if the data have been successfully processed.
Definition: json_feed.cc:74
bool needData() const
Checks if the model needs additional data to continue.
Definition: json_feed.cc:68
static const int STRING_JSON_ST
Parsing JSON string.
Definition: json_feed.h:88
static const int INNER_JSON_ST
Parsing JSON.
Definition: json_feed.h:85
static const int JSON_START_ST
Found first opening brace or square bracket.
Definition: json_feed.h:82
void poll()
Runs the model as long as data is available.
Definition: json_feed.cc:53
static const int FEED_FAILED_EVT
Invalid syntax detected.
Definition: json_feed.h:128
static const int MORE_DATA_PROVIDED_EVT
New data provided and parsing should continue.
Definition: json_feed.h:122
void initModel()
Initializes state model.
Definition: json_feed.cc:41
static const int FEED_OK_EVT
Found opening brace and the matching closing brace.
Definition: json_feed.h:125
data::ElementPtr toElement() const
Returns processed data as a structure of isc::data::Element objects.
Definition: json_feed.cc:80
static const int RECEIVE_START_ST
State indicating a beginning of a feed.
Definition: json_feed.h:76
static const int NEED_MORE_DATA_EVT
Unable to proceed with parsing until new data is provided.
Definition: json_feed.h:119
static const int DATA_READ_OK_EVT
Chunk of data successfully read and parsed.
Definition: json_feed.h:116
JSONFeed()
Constructor.
Definition: json_feed.cc:35
static const int FEED_OK_ST
Found opening and closing brace or square bracket.
Definition: json_feed.h:101
static const int JSON_END_ST
Found last closing brace or square bracket.
Definition: json_feed.h:94
static ElementPtr fromWire(std::stringstream &in, int length)
These function pparse the wireformat at the given stringstream (of the given length).
Definition: data.cc:927
Implements a finite state machine.
Definition: state_model.h:271
const EventPtr & getEvent(unsigned int value)
Fetches the event referred to by value.
Definition: state_model.cc:184
void initDictionaries()
Initializes the event and state dictionaries.
Definition: state_model.cc:146
bool isModelDone() const
Returns whether or not the model has finished execution.
Definition: state_model.cc:365
virtual void defineEvents()
Populates the set of events.
Definition: state_model.cc:221
void postNextEvent(unsigned int event)
Sets the next event to the given event value.
Definition: state_model.cc:304
void defineState(unsigned int value, const std::string &label, StateHandler handler, const StatePausing &state_pausing=STATE_PAUSE_NEVER)
Adds an state value and associated label to the set of states.
Definition: state_model.cc:194
const StatePtr getState(unsigned int value)
Fetches the state referred to by value.
Definition: state_model.cc:211
unsigned int getNextEvent() const
Fetches the model's next event.
Definition: state_model.cc:346
void defineEvent(unsigned int value, const std::string &label)
Adds an event value and associated label to the set of events.
Definition: state_model.cc:168
void transition(unsigned int state, unsigned int event)
Sets up the model to transition into given state with a given event.
Definition: state_model.cc:256
virtual void verifyEvents()
Validates the contents of the set of events.
Definition: state_model.cc:229
static const int END_EVT
Event issued to end the model execution.
Definition: state_model.h:295
static const int NOP_EVT
Signifies that no event has occurred.
Definition: state_model.h:289
static const int START_EVT
Event issued to start the model execution.
Definition: state_model.h:292
void abortModel(const std::string &explanation)
Aborts model execution.
Definition: state_model.cc:272
std::string getEventLabel(const int event) const
Fetches the label associated with an event value.
Definition: state_model.cc:385
virtual void defineStates()
Populates the set of states.
Definition: state_model.cc:237
void setState(unsigned int state)
Sets the current state to the given state value.
Definition: state_model.cc:281
static const int END_ST
Final state, all the state model has reached its conclusion.
Definition: state_model.h:279
unsigned int getLastEvent() const
Fetches the model's last event.
Definition: state_model.cc:341
unsigned int getCurrState() const
Fetches the model's current state.
Definition: state_model.cc:331
string & output_
Definition: dns/message.cc:877
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< Element > ElementPtr
Definition: data.h:22
Definition: edns.h:19
Defines the logger used by the top-level component of kea-dhcp-ddns.