Line data Source code
1 : /*
2 : * Copyright (c) 2018 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #ifndef _SANDESH_PROTOCOL_TJSONPROTOCOL_H_
7 : #define _SANDESH_PROTOCOL_TJSONPROTOCOL_H_ 1
8 :
9 : #include <string.h>
10 : #include "TVirtualProtocol.h"
11 :
12 : #include <boost/shared_ptr.hpp>
13 : #include <boost/tokenizer.hpp>
14 : #include <boost/algorithm/string.hpp>
15 : #include <boost/algorithm/string/replace.hpp>
16 : #include <boost/container/set.hpp>
17 : #include <base/time_util.h>
18 :
19 : namespace contrail { namespace sandesh { namespace protocol {
20 :
21 : /**
22 : * Protocol that prints the payload in JSON format.
23 : */
24 : class TJSONProtocol : public TVirtualProtocol<TJSONProtocol> {
25 : private:
26 : enum write_state_t
27 : { UNINIT
28 : , STRUCT
29 : , LIST
30 : , SET
31 : , MAP
32 : , SNDESH
33 : };
34 :
35 : public:
36 : TJSONProtocol(boost::shared_ptr<TTransport> trans)
37 : : TVirtualProtocol<TJSONProtocol>(trans)
38 : , trans_(trans.get())
39 : , string_limit_(DEFAULT_STRING_LIMIT)
40 : , string_prefix_size_(DEFAULT_STRING_PREFIX_SIZE)
41 : , reader_(*trans)
42 : {
43 : TType ttypes_arr[] = { T_STRUCT, T_MAP, T_SET, T_LIST, T_SANDESH };
44 : complexTypeSet[T_STRUCT] = true;
45 : complexTypeSet[T_MAP] = true;
46 : complexTypeSet[T_SET] = true;
47 : complexTypeSet[T_LIST] = true;
48 : write_state_.push_back(UNINIT);
49 : }
50 :
51 : static const int32_t DEFAULT_STRING_LIMIT = 256;
52 : static const int32_t DEFAULT_STRING_PREFIX_SIZE = 16;
53 :
54 : void setStringSizeLimit(int32_t string_limit) {
55 : string_limit_ = string_limit;
56 : }
57 :
58 : void setStringPrefixSize(int32_t string_prefix_size) {
59 : string_prefix_size_ = string_prefix_size;
60 : }
61 :
62 0 : static std::string escapeJSONControlCharsInternal(const std::string& str) {
63 0 : std::string xmlstr;
64 0 : xmlstr.reserve(str.length());
65 0 : for (std::string::const_iterator it = str.begin();
66 0 : it != str.end(); ++it) {
67 0 : switch(*it) {
68 0 : case '&': xmlstr += "&"; break;
69 0 : case '\'': xmlstr += "'"; break;
70 0 : case '<': xmlstr += "<"; break;
71 0 : case '>': xmlstr += ">"; break;
72 0 : default: xmlstr += *it;
73 : }
74 : }
75 0 : return xmlstr;
76 0 : }
77 :
78 0 : static std::string escapeJSONControlChars(const std::string& str) {
79 0 : if (strpbrk(str.c_str(), "&'<>") != NULL) {
80 0 : return escapeJSONControlCharsInternal(str);
81 : } else {
82 0 : return str;
83 : }
84 : }
85 :
86 : static void unescapeJSONControlChars(std::string& str) {
87 : boost::algorithm::replace_all(str, "&", "&");
88 : boost::algorithm::replace_all(str, "'", "\'");
89 : boost::algorithm::replace_all(str, "<", "<");
90 : boost::algorithm::replace_all(str, ">", ">");
91 : }
92 :
93 : /**
94 : * Writing functions
95 : */
96 :
97 : int32_t writeMessageBegin(const std::string& name,
98 : const TMessageType messageType,
99 : const int32_t seqid);
100 :
101 : int32_t writeMessageEnd();
102 :
103 : int32_t writeStructBegin(const char* name);
104 :
105 : int32_t writeStructEnd();
106 :
107 : int32_t writeSandeshBegin(const char* name);
108 :
109 : int32_t writeSandeshEnd();
110 :
111 : int32_t writeContainerElementBegin();
112 :
113 : int32_t writeContainerElementEnd();
114 :
115 : int32_t writeFieldBegin(const char* name,
116 : const TType fieldType,
117 : const int16_t fieldId,
118 : const std::map<std::string, std::string> *const amap = NULL);
119 :
120 : int32_t writeFieldEnd();
121 :
122 : int32_t writeFieldStop();
123 :
124 : int32_t writeMapBegin(const TType keyType,
125 : const TType valType,
126 : const uint32_t size);
127 :
128 : int32_t writeMapEnd();
129 :
130 : int32_t writeListBegin(const TType elemType,
131 : const uint32_t size);
132 :
133 : int32_t writeListEnd();
134 :
135 : int32_t writeSetBegin(const TType elemType,
136 : const uint32_t size);
137 :
138 : int32_t writeSetEnd();
139 :
140 : int32_t writeBool(const bool value);
141 :
142 : int32_t writeByte(const int8_t byte);
143 :
144 : int32_t writeI16(const int16_t i16);
145 :
146 : int32_t writeI32(const int32_t i32);
147 :
148 : int32_t writeI64(const int64_t i64);
149 :
150 : int32_t writeU16(const uint16_t u16);
151 :
152 : int32_t writeU32(const uint32_t u32);
153 :
154 : int32_t writeU64(const uint64_t u64);
155 :
156 : int32_t writeIPV4(const uint32_t ip4);
157 :
158 : int32_t writeIPADDR(const boost::asio::ip::address& ipaddress);
159 :
160 : int32_t writeDouble(const double dub);
161 :
162 : int32_t writeString(const std::string& str);
163 :
164 : int32_t writeBinary(const std::string& str);
165 :
166 : int32_t writeJSON(const std::string& str);
167 :
168 : int32_t writeUUID(const boost::uuids::uuid& uuid);
169 :
170 : /**
171 : * Reading functions
172 : */
173 : void setSandeshEnd(bool val) {
174 : sandesh_end_ = val;
175 : }
176 :
177 : class LookaheadReader {
178 :
179 : public:
180 :
181 : LookaheadReader(TTransport &trans) :
182 : trans_(&trans),
183 : hasData_(false),
184 : has2Data_(false),
185 : firstRead_(false) {
186 : }
187 :
188 : uint8_t read() {
189 : if (hasData_) {
190 : hasData_ = false;
191 : }
192 : else {
193 : if (has2Data_) {
194 : if (firstRead_) {
195 : has2Data_ = false;
196 : firstRead_ = false;
197 : return data2_[1];
198 : } else {
199 : firstRead_ = true;
200 : return data2_[0];
201 : }
202 : } else {
203 : trans_->readAll(&data_, 1);
204 : }
205 : }
206 : return data_;
207 : }
208 :
209 : uint8_t peek() {
210 : if (!hasData_) {
211 : trans_->readAll(&data_, 1);
212 : }
213 : hasData_ = true;
214 : return data_;
215 : }
216 :
217 : uint8_t peek2() {
218 : bool first = false;
219 : if (!has2Data_) {
220 : trans_->readAll(data2_, 2);
221 : first = true;
222 : }
223 : has2Data_ = true;
224 : return first ? data2_[0] : data2_[1];
225 : }
226 :
227 : private:
228 : TTransport *trans_;
229 : bool hasData_;
230 : uint8_t data_;
231 : bool has2Data_;
232 : uint8_t data2_[2];
233 : bool firstRead_;
234 : };
235 :
236 : private:
237 : typedef boost::tokenizer<boost::char_separator<char> >
238 : tokenizer;
239 : void indentUp();
240 : void indentDown();
241 : int32_t writePlain(const std::string& str);
242 : int32_t writeIndented(const std::string& str);
243 :
244 : static const std::string& fieldTypeName(TType type);
245 : static TType getTypeIDForTypeName(const std::string &name);
246 :
247 : TTransport* trans_;
248 :
249 : int32_t string_limit_;
250 : int32_t string_prefix_size_;
251 :
252 : std::string indent_str_;
253 :
254 : static const int indent_inc = 2;
255 :
256 : std::vector<write_state_t> write_state_;
257 :
258 : bool sandesh_begin_;
259 :
260 : bool sandesh_end_;
261 :
262 : std::vector<bool> is_struct_begin_list_;
263 :
264 : std::vector<bool> is_list_begin_list_;
265 :
266 : bool is_primitive_list_begin_;
267 :
268 : bool is_first_primitve_list_elem_;
269 :
270 : bool is_data_map_key_;
271 :
272 : bool is_beginning_of_map;
273 :
274 : bool is_string_begin_;
275 :
276 : bool is_struct_begin_;
277 :
278 : bool in_list_context_;
279 :
280 : bool is_list_begin_;
281 :
282 : bool is_map_begin_;
283 :
284 : bool in_map_context_;
285 :
286 : bool in_non_primitive_map_context_;
287 :
288 : bool in_primitive_list_context_;
289 :
290 : bool in_non_primitive_list_context_;
291 :
292 : bool is_map_primitive_;
293 :
294 : bool is_map_val_;
295 :
296 : bool is_list_elem_string_;
297 :
298 : std::vector<std::string> current_sandesh_context_;
299 :
300 : std::vector<bool> is_first_element_context_;
301 :
302 : std::vector<bool> is_primitive_element_list_;
303 :
304 : std::vector<bool> is_map_val_primitive_;
305 :
306 : std::vector<bool> in_map_val_context_;
307 : std::vector<std::string> xml_state_;
308 : LookaheadReader reader_;
309 : std::map<TType, bool> complexTypeSet;
310 :
311 : };
312 :
313 : /**
314 : * Constructs JSON protocol handlers
315 : */
316 : class TJSONProtocolFactory : public TProtocolFactory {
317 : public:
318 : TJSONProtocolFactory() {}
319 : virtual ~TJSONProtocolFactory() {}
320 :
321 : boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) {
322 : return boost::shared_ptr<TProtocol>(new TJSONProtocol(trans));
323 : }
324 :
325 : };
326 :
327 : }}} // contrail::sandesh::protocol
328 :
329 : #endif // #ifndef _SANDESH_PROTOCOL_TJSONPROTOCOL_H_
330 :
331 :
|