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