1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
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 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <thrift/lib/cpp/protocol/TJSONProtocol.h>
18
19 #include <math.h>
20 #include <folly/Conv.h>
21 #include <folly/dynamic.h>
22 #include <folly/json.h>
23 #include <thrift/lib/cpp/protocol/TBase64Utils.h>
24 #include <thrift/lib/cpp/transport/TTransportException.h>
25
26 using namespace apache::thrift::transport;
27
28 namespace apache {
29 namespace thrift {
30 namespace protocol {
31
32 // Static data
33 const uint8_t TJSONProtocol::kJSONObjectStart = '{';
34 const uint8_t TJSONProtocol::kJSONObjectEnd = '}';
35 const uint8_t TJSONProtocol::kJSONArrayStart = '[';
36 const uint8_t TJSONProtocol::kJSONArrayEnd = ']';
37 const uint8_t TJSONProtocol::kJSONPairSeparator = ':';
38 const uint8_t TJSONProtocol::kJSONElemSeparator = ',';
39 const uint8_t TJSONProtocol::kJSONBackslash = '\\';
40 const uint8_t TJSONProtocol::kJSONStringDelimiter = '"';
41 const uint8_t TJSONProtocol::kJSONZeroChar = '0';
42 const uint8_t TJSONProtocol::kJSONEscapeChar = 'u';
43 const uint8_t TJSONProtocol::kJSONSpace = ' ';
44 const uint8_t TJSONProtocol::kJSONNewline = '\n';
45 const uint8_t TJSONProtocol::kJSONTab = '\t';
46 const uint8_t TJSONProtocol::kJSONCarriageReturn = '\r';
47
48 const std::string TJSONProtocol::kJSONEscapePrefix("\\u00");
49
50 const std::string TJSONProtocol::kJSONTrue("true");
51 const std::string TJSONProtocol::kJSONFalse("false");
52
53 const uint32_t TJSONProtocol::kThriftVersion1 = 1;
54
55 const std::string TJSONProtocol::kThriftNan("NaN");
56 const std::string TJSONProtocol::kThriftNegativeNan("-NaN");
57 const std::string TJSONProtocol::kThriftInfinity("Infinity");
58 const std::string TJSONProtocol::kThriftNegativeInfinity("-Infinity");
59
60 const std::string TJSONProtocol::kTypeNameBool("tf");
61 const std::string TJSONProtocol::kTypeNameByte("i8");
62 const std::string TJSONProtocol::kTypeNameI16("i16");
63 const std::string TJSONProtocol::kTypeNameI32("i32");
64 const std::string TJSONProtocol::kTypeNameI64("i64");
65 const std::string TJSONProtocol::kTypeNameDouble("dbl");
66 const std::string TJSONProtocol::kTypeNameFloat("flt");
67 const std::string TJSONProtocol::kTypeNameStruct("rec");
68 const std::string TJSONProtocol::kTypeNameString("str");
69 const std::string TJSONProtocol::kTypeNameMap("map");
70 const std::string TJSONProtocol::kTypeNameList("lst");
71 const std::string TJSONProtocol::kTypeNameSet("set");
72
getTypeNameForTypeID(TType typeID)73 const std::string& TJSONProtocol::getTypeNameForTypeID(TType typeID) {
74 switch (typeID) {
75 case T_BOOL:
76 return kTypeNameBool;
77 case T_BYTE:
78 return kTypeNameByte;
79 case T_I16:
80 return kTypeNameI16;
81 case T_I32:
82 return kTypeNameI32;
83 case T_I64:
84 return kTypeNameI64;
85 case T_DOUBLE:
86 return kTypeNameDouble;
87 case T_FLOAT:
88 return kTypeNameFloat;
89 case T_STRING:
90 return kTypeNameString;
91 case T_STRUCT:
92 return kTypeNameStruct;
93 case T_MAP:
94 return kTypeNameMap;
95 case T_SET:
96 return kTypeNameSet;
97 case T_LIST:
98 return kTypeNameList;
99 default:
100 throw TProtocolException(
101 TProtocolException::NOT_IMPLEMENTED, "Unrecognized type");
102 }
103 }
104
getTypeIDForTypeName(const std::string & name)105 TType TJSONProtocol::getTypeIDForTypeName(const std::string& name) {
106 TType result = T_STOP; // Sentinel value
107 if (name.length() > 1) {
108 switch (name[0]) {
109 case 'd':
110 result = T_DOUBLE;
111 break;
112 case 'f':
113 result = T_FLOAT;
114 break;
115 case 'i':
116 switch (name[1]) {
117 case '8':
118 result = T_BYTE;
119 break;
120 case '1':
121 result = T_I16;
122 break;
123 case '3':
124 result = T_I32;
125 break;
126 case '6':
127 result = T_I64;
128 break;
129 }
130 break;
131 case 'l':
132 result = T_LIST;
133 break;
134 case 'm':
135 result = T_MAP;
136 break;
137 case 'r':
138 result = T_STRUCT;
139 break;
140 case 's':
141 if (name[1] == 't') {
142 result = T_STRING;
143 } else if (name[1] == 'e') {
144 result = T_SET;
145 }
146 break;
147 case 't':
148 result = T_BOOL;
149 break;
150 }
151 }
152 if (result == T_STOP) {
153 throw TProtocolException(
154 TProtocolException::NOT_IMPLEMENTED, "Unrecognized type");
155 }
156 return result;
157 }
158
159 // This table describes the handling for the first 0x30 characters
160 // 0 : escape using "\u00xx" notation
161 // 1 : just output index
162 // <other> : escape using "\<other>" notation
163 static const uint8_t kJSONCharTable[0x30] = {
164 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
165 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, // 0
166 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
167 1, 1, '"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
168 };
169
170 // This string's characters must match up with the elements in kEscapeCharVals.
171 // I don't have '/' on this list even though it appears on www.json.org --
172 // it is not in the RFC
173 const static std::string kEscapeChars("\"\\/bfnrt");
174
175 // The elements of this array must match up with the sequence of characters in
176 // kEscapeChars
177 const static uint8_t kEscapeCharVals[8] = {
178 '"',
179 '\\',
180 '/',
181 '\b',
182 '\f',
183 '\n',
184 '\r',
185 '\t',
186 };
187
188 // Static helper functions
189
190 // Reads any whitespace characters
skipWhitespace(TJSONProtocol::LookaheadReader & reader)191 static uint32_t skipWhitespace(TJSONProtocol::LookaheadReader& reader) {
192 uint32_t result = 0;
193
194 while (reader.canPeek()) {
195 uint8_t ch = reader.peek();
196 if (ch != TJSONProtocol::kJSONSpace && ch != TJSONProtocol::kJSONNewline &&
197 ch != TJSONProtocol::kJSONTab &&
198 ch != TJSONProtocol::kJSONCarriageReturn) {
199 break;
200 }
201 reader.read();
202 ++result;
203 }
204
205 return result;
206 }
207
208 // Read 1 character from the transport trans and verify that it is the
209 // expected character ch.
210 // Throw a protocol exception if it is not.
readSyntaxChar(TJSONProtocol::LookaheadReader & reader,uint8_t ch)211 static uint32_t readSyntaxChar(
212 TJSONProtocol::LookaheadReader& reader, uint8_t ch) {
213 uint8_t ch2 = reader.read();
214 if (ch2 != ch) {
215 throw TProtocolException(
216 TProtocolException::INVALID_DATA,
217 "Expected \'" + std::string((char*)&ch, 1) + "\'; got \'" +
218 std::string((char*)&ch2, 1) + "\'.");
219 }
220 return 1;
221 }
222
223 // Reads a structural character (any of '[', ']', '{', '}', ',' and ':'),
224 // and any whitespace characters around it
readStructuralChar(TJSONProtocol::LookaheadReader & reader,uint8_t ch)225 static uint32_t readStructuralChar(
226 TJSONProtocol::LookaheadReader& reader, uint8_t ch) {
227 assert(
228 ch == TJSONProtocol::kJSONObjectStart ||
229 ch == TJSONProtocol::kJSONObjectEnd ||
230 ch == TJSONProtocol::kJSONArrayStart ||
231 ch == TJSONProtocol::kJSONArrayEnd ||
232 ch == TJSONProtocol::kJSONPairSeparator ||
233 ch == TJSONProtocol::kJSONElemSeparator);
234
235 uint32_t result = 0;
236 result += skipWhitespace(reader);
237 result += readSyntaxChar(reader, ch);
238 result += skipWhitespace(reader);
239
240 return result;
241 }
242
243 // Return the integer value of a hex character ch.
244 // Throw a protocol exception if the character is not [0-9a-f].
hexVal(uint8_t ch)245 static uint8_t hexVal(uint8_t ch) {
246 if ((ch >= '0') && (ch <= '9')) {
247 return ch - '0';
248 } else if ((ch >= 'a') && (ch <= 'f')) {
249 return ch - 'a' + 10;
250 } else {
251 throw TProtocolException(
252 TProtocolException::INVALID_DATA,
253 "Expected hex val ([0-9a-f]); got \'" + std::string((char*)&ch, 1) +
254 "\'.");
255 }
256 }
257
258 // Return the hex character representing the integer val. The value is masked
259 // to make sure it is in the correct range.
hexChar(uint8_t val)260 static uint8_t hexChar(uint8_t val) {
261 val &= 0x0F;
262 if (val < 10) {
263 return val + '0';
264 } else {
265 return val - 10 + 'a';
266 }
267 }
268
269 // Return true if the character ch is in [-+0-9.Ee]; false otherwise
isJSONNumeric(uint8_t ch)270 static bool isJSONNumeric(uint8_t ch) {
271 switch (ch) {
272 case '+':
273 case '-':
274 case '.':
275 case '0':
276 case '1':
277 case '2':
278 case '3':
279 case '4':
280 case '5':
281 case '6':
282 case '7':
283 case '8':
284 case '9':
285 case 'E':
286 case 'e':
287 return true;
288 }
289 return false;
290 }
291
292 /**
293 * Class to serve as base JSON context and as base class for other context
294 * implementations
295 */
296 class TJSONContext {
297 public:
TJSONContext()298 TJSONContext() {}
299
~TJSONContext()300 virtual ~TJSONContext() {}
301
302 /**
303 * Write context data to the transport. Default is to do nothing.
304 */
write(TTransport &)305 virtual uint32_t write(TTransport& /*trans*/) { return 0; }
306
307 /**
308 * Read context data from the transport. Default is to do nothing.
309 */
read(TJSONProtocol::LookaheadReader &)310 virtual uint32_t read(TJSONProtocol::LookaheadReader& /*reader*/) {
311 return 0;
312 }
313
314 /**
315 * Return true if numbers need to be escaped as strings in this context.
316 * Default behavior is to return false.
317 */
escapeNum()318 virtual bool escapeNum() { return false; }
319 };
320
321 // Context class for object member key-value pairs
322 class JSONPairContext : public TJSONContext {
323 public:
JSONPairContext()324 JSONPairContext() : first_(true), colon_(true) {}
325
write(TTransport & trans)326 uint32_t write(TTransport& trans) override {
327 if (first_) {
328 first_ = false;
329 colon_ = true;
330 return 0;
331 } else {
332 trans.write(
333 colon_ ? &TJSONProtocol::kJSONPairSeparator
334 : &TJSONProtocol::kJSONElemSeparator,
335 1);
336 colon_ = !colon_;
337 return 1;
338 }
339 }
340
read(TJSONProtocol::LookaheadReader & reader)341 uint32_t read(TJSONProtocol::LookaheadReader& reader) override {
342 if (first_) {
343 first_ = false;
344 colon_ = true;
345 return 0;
346 } else {
347 uint8_t ch =
348 (colon_ ? TJSONProtocol::kJSONPairSeparator
349 : TJSONProtocol::kJSONElemSeparator);
350 colon_ = !colon_;
351 return readStructuralChar(reader, ch);
352 }
353 }
354
355 // Numbers must be turned into strings if they are the key part of a pair
escapeNum()356 bool escapeNum() override { return colon_; }
357
358 private:
359 bool first_;
360 bool colon_;
361 };
362
363 // Context class for lists
364 class JSONListContext : public TJSONContext {
365 public:
JSONListContext()366 JSONListContext() : first_(true) {}
367
write(TTransport & trans)368 uint32_t write(TTransport& trans) override {
369 if (first_) {
370 first_ = false;
371 return 0;
372 } else {
373 trans.write(&TJSONProtocol::kJSONElemSeparator, 1);
374 return 1;
375 }
376 }
377
read(TJSONProtocol::LookaheadReader & reader)378 uint32_t read(TJSONProtocol::LookaheadReader& reader) override {
379 if (first_) {
380 first_ = false;
381 return 0;
382 } else {
383 return readStructuralChar(reader, TJSONProtocol::kJSONElemSeparator);
384 }
385 }
386
387 private:
388 bool first_;
389 };
390
TJSONProtocol(std::shared_ptr<TTransport> ptrans)391 TJSONProtocol::TJSONProtocol(std::shared_ptr<TTransport> ptrans)
392 : TVirtualProtocol<TJSONProtocol>(ptrans),
393 trans_(ptrans.get()),
394 context_(new TJSONContext()),
395 allowDecodeUTF8_(false),
396 reader_(*ptrans) {}
397
TJSONProtocol(TTransport * ptrans)398 TJSONProtocol::TJSONProtocol(TTransport* ptrans)
399 : TVirtualProtocol<TJSONProtocol>(ptrans),
400 trans_(ptrans),
401 context_(new TJSONContext()),
402 allowDecodeUTF8_(false),
403 reader_(*ptrans) {}
404
~TJSONProtocol()405 TJSONProtocol::~TJSONProtocol() {}
406
pushContext(std::shared_ptr<TJSONContext> c)407 void TJSONProtocol::pushContext(std::shared_ptr<TJSONContext> c) {
408 contexts_.push(context_);
409 context_ = c;
410 }
411
popContext()412 void TJSONProtocol::popContext() {
413 context_ = contexts_.top();
414 contexts_.pop();
415 }
416
417 // Write the character ch as a JSON escape sequence ("\u00xx")
writeJSONEscapeChar(uint8_t ch)418 uint32_t TJSONProtocol::writeJSONEscapeChar(uint8_t ch) {
419 trans_->write(
420 (const uint8_t*)kJSONEscapePrefix.c_str(), kJSONEscapePrefix.length());
421 uint8_t outCh = hexChar(ch >> 4);
422 trans_->write(&outCh, 1);
423 outCh = hexChar(ch);
424 trans_->write(&outCh, 1);
425 return 6;
426 }
427
428 // Write the character ch as part of a JSON string, escaping as appropriate.
writeJSONChar(uint8_t ch)429 uint32_t TJSONProtocol::writeJSONChar(uint8_t ch) {
430 if (ch >= 0x30) {
431 if (ch == kJSONBackslash) { // Only special character >= 0x30 is '\'
432 trans_->write(&kJSONBackslash, 1);
433 trans_->write(&kJSONBackslash, 1);
434 return 2;
435 } else {
436 trans_->write(&ch, 1);
437 return 1;
438 }
439 } else {
440 uint8_t outCh = kJSONCharTable[ch];
441 // Check if regular character, backslash escaped, or JSON escaped
442 if (outCh == 1) {
443 trans_->write(&ch, 1);
444 return 1;
445 } else if (outCh > 1) {
446 trans_->write(&kJSONBackslash, 1);
447 trans_->write(&outCh, 1);
448 return 2;
449 } else {
450 return writeJSONEscapeChar(ch);
451 }
452 }
453 }
454
455 // Write out the contents of the string str as a JSON string, escaping
456 // characters as appropriate.
writeJSONString(const std::string & str)457 uint32_t TJSONProtocol::writeJSONString(const std::string& str) {
458 uint32_t result = context_->write(*trans_);
459 result += 2; // For quotes
460 trans_->write(&kJSONStringDelimiter, 1);
461 std::string::const_iterator iter(str.begin());
462 std::string::const_iterator end(str.end());
463 while (iter != end) {
464 result += writeJSONChar(*iter++);
465 }
466 trans_->write(&kJSONStringDelimiter, 1);
467 return result;
468 }
469
470 // Write out the contents of the string as JSON string, base64-encoding
471 // the string's contents, and escaping as appropriate
writeJSONBase64(const std::string & str)472 uint32_t TJSONProtocol::writeJSONBase64(const std::string& str) {
473 uint32_t result = context_->write(*trans_);
474 result += 2; // For quotes
475 trans_->write(&kJSONStringDelimiter, 1);
476 uint8_t b[4];
477 const uint8_t* bytes = (const uint8_t*)str.c_str();
478 uint32_t len = str.length();
479 while (len >= 3) {
480 // Encode 3 bytes at a time
481 base64_encode(bytes, 3, b);
482 trans_->write(b, 4);
483 result += 4;
484 bytes += 3;
485 len -= 3;
486 }
487 if (len) { // Handle remainder
488 base64_encode(bytes, len, b);
489 trans_->write(b, len + 1);
490 result += len + 1;
491 }
492 trans_->write(&kJSONStringDelimiter, 1);
493 return result;
494 }
495
496 // Convert the given integer type to a JSON number, or a string
497 // if the context requires it (eg: key in a map pair).
498 template <typename NumberType>
writeJSONInteger(NumberType num)499 uint32_t TJSONProtocol::writeJSONInteger(NumberType num) {
500 uint32_t result = context_->write(*trans_);
501 auto val = folly::to<std::string>(num);
502 bool escapeNum = context_->escapeNum();
503 if (escapeNum) {
504 trans_->write(&kJSONStringDelimiter, 1);
505 result += 1;
506 }
507 trans_->write((const uint8_t*)val.c_str(), val.length());
508 result += val.length();
509 if (escapeNum) {
510 trans_->write(&kJSONStringDelimiter, 1);
511 result += 1;
512 }
513 return result;
514 }
515
516 // Convert the given boolean type to a true/false token
writeJSONBool(const bool value)517 uint32_t TJSONProtocol::writeJSONBool(const bool value) {
518 uint32_t result = context_->write(*trans_);
519 result += 1;
520
521 bool escapeNum = context_->escapeNum();
522 if (escapeNum) {
523 trans_->write(&kJSONStringDelimiter, 1);
524 result += 1;
525 }
526
527 std::string boolVal = value ? "true" : "false";
528
529 std::string::const_iterator iter(boolVal.begin());
530 std::string::const_iterator end(boolVal.end());
531 while (iter != end) {
532 result += writeJSONChar(*iter++);
533 }
534
535 if (escapeNum) {
536 trans_->write(&kJSONStringDelimiter, 1);
537 result += 1;
538 }
539
540 return result;
541 }
542
543 // Convert the given double to a JSON string, which is either the number,
544 // "NaN" or "Infinity" or "-Infinity".
545 template <typename NumberType>
writeJSONDouble(NumberType num)546 uint32_t TJSONProtocol::writeJSONDouble(NumberType num) {
547 uint32_t result = context_->write(*trans_);
548
549 std::string val;
550 bool special = true;
551 if (num == std::numeric_limits<NumberType>::infinity()) {
552 val = kThriftInfinity;
553 } else if (num == -std::numeric_limits<NumberType>::infinity()) {
554 val = kThriftNegativeInfinity;
555 } else if (std::isnan(num)) {
556 val = kThriftNan;
557 } else {
558 special = false;
559 val = folly::to<std::string>(num);
560 }
561
562 bool escapeNum = special || context_->escapeNum();
563 if (escapeNum) {
564 trans_->write(&kJSONStringDelimiter, 1);
565 result += 1;
566 }
567 trans_->write((const uint8_t*)val.c_str(), val.length());
568 result += val.length();
569 if (escapeNum) {
570 trans_->write(&kJSONStringDelimiter, 1);
571 result += 1;
572 }
573 return result;
574 }
575
writeJSONObjectStart()576 uint32_t TJSONProtocol::writeJSONObjectStart() {
577 uint32_t result = context_->write(*trans_);
578 trans_->write(&kJSONObjectStart, 1);
579 pushContext(std::shared_ptr<TJSONContext>(new JSONPairContext()));
580 return result + 1;
581 }
582
writeJSONObjectEnd()583 uint32_t TJSONProtocol::writeJSONObjectEnd() {
584 popContext();
585 trans_->write(&kJSONObjectEnd, 1);
586 return 1;
587 }
588
writeJSONArrayStart()589 uint32_t TJSONProtocol::writeJSONArrayStart() {
590 uint32_t result = context_->write(*trans_);
591 trans_->write(&kJSONArrayStart, 1);
592 pushContext(std::shared_ptr<TJSONContext>(new JSONListContext()));
593 return result + 1;
594 }
595
writeJSONArrayEnd()596 uint32_t TJSONProtocol::writeJSONArrayEnd() {
597 popContext();
598 trans_->write(&kJSONArrayEnd, 1);
599 return 1;
600 }
601
writeMessageBegin(const std::string & name,const TMessageType messageType,const int32_t seqid)602 uint32_t TJSONProtocol::writeMessageBegin(
603 const std::string& name,
604 const TMessageType messageType,
605 const int32_t seqid) {
606 uint32_t result = writeJSONArrayStart();
607 result += writeJSONInteger(kThriftVersion1);
608 result += writeJSONString(name);
609 result += writeJSONInteger(messageType);
610 result += writeJSONInteger(seqid);
611 return result;
612 }
613
writeMessageEnd()614 uint32_t TJSONProtocol::writeMessageEnd() {
615 return writeJSONArrayEnd();
616 }
617
writeStructBegin(const char *)618 uint32_t TJSONProtocol::writeStructBegin(const char* /*name*/) {
619 return writeJSONObjectStart();
620 }
621
writeStructEnd()622 uint32_t TJSONProtocol::writeStructEnd() {
623 return writeJSONObjectEnd();
624 }
625
writeFieldBegin(const char *,const TType fieldType,const int16_t fieldId)626 uint32_t TJSONProtocol::writeFieldBegin(
627 const char* /*name*/, const TType fieldType, const int16_t fieldId) {
628 uint32_t result = writeJSONInteger(fieldId);
629 result += writeJSONObjectStart();
630 result += writeJSONString(getTypeNameForTypeID(fieldType));
631 return result;
632 }
633
writeFieldEnd()634 uint32_t TJSONProtocol::writeFieldEnd() {
635 return writeJSONObjectEnd();
636 }
637
writeFieldStop()638 uint32_t TJSONProtocol::writeFieldStop() {
639 return 0;
640 }
641
writeMapBegin(const TType keyType,const TType valType,const uint32_t size)642 uint32_t TJSONProtocol::writeMapBegin(
643 const TType keyType, const TType valType, const uint32_t size) {
644 uint32_t result = writeJSONArrayStart();
645 result += writeJSONString(getTypeNameForTypeID(keyType));
646 result += writeJSONString(getTypeNameForTypeID(valType));
647 result += writeJSONInteger((int64_t)size);
648 result += writeJSONObjectStart();
649 return result;
650 }
651
writeMapEnd()652 uint32_t TJSONProtocol::writeMapEnd() {
653 return writeJSONObjectEnd() + writeJSONArrayEnd();
654 }
655
writeListBegin(const TType elemType,const uint32_t size)656 uint32_t TJSONProtocol::writeListBegin(
657 const TType elemType, const uint32_t size) {
658 uint32_t result = writeJSONArrayStart();
659 result += writeJSONString(getTypeNameForTypeID(elemType));
660 result += writeJSONInteger((int64_t)size);
661 return result;
662 }
663
writeListEnd()664 uint32_t TJSONProtocol::writeListEnd() {
665 return writeJSONArrayEnd();
666 }
667
writeSetBegin(const TType elemType,const uint32_t size)668 uint32_t TJSONProtocol::writeSetBegin(
669 const TType elemType, const uint32_t size) {
670 uint32_t result = writeJSONArrayStart();
671 result += writeJSONString(getTypeNameForTypeID(elemType));
672 result += writeJSONInteger((int64_t)size);
673 return result;
674 }
675
writeSetEnd()676 uint32_t TJSONProtocol::writeSetEnd() {
677 return writeJSONArrayEnd();
678 }
679
writeBool(const bool value)680 uint32_t TJSONProtocol::writeBool(const bool value) {
681 return writeJSONInteger(value);
682 }
683
writeByte(const int8_t byte)684 uint32_t TJSONProtocol::writeByte(const int8_t byte) {
685 // writeByte() must be handled specially because folly::to sees
686 // int8_t as a text type instead of an integer type
687 return writeJSONInteger((int16_t)byte);
688 }
689
writeI16(const int16_t i16)690 uint32_t TJSONProtocol::writeI16(const int16_t i16) {
691 return writeJSONInteger(i16);
692 }
693
writeI32(const int32_t i32)694 uint32_t TJSONProtocol::writeI32(const int32_t i32) {
695 return writeJSONInteger(i32);
696 }
697
writeI64(const int64_t i64)698 uint32_t TJSONProtocol::writeI64(const int64_t i64) {
699 return writeJSONInteger(i64);
700 }
701
writeDouble(const double dub)702 uint32_t TJSONProtocol::writeDouble(const double dub) {
703 return writeJSONDouble(dub);
704 }
705
writeFloat(const float flt)706 uint32_t TJSONProtocol::writeFloat(const float flt) {
707 return writeJSONDouble(flt);
708 }
709
writeString(const std::string & str)710 uint32_t TJSONProtocol::writeString(const std::string& str) {
711 return writeJSONString(str);
712 }
713
writeBinary(const std::string & str)714 uint32_t TJSONProtocol::writeBinary(const std::string& str) {
715 return writeJSONBase64(str);
716 }
717
718 /**
719 * Reading functions
720 */
721
722 // Skips any whitespace characters
skipJSONWhitespace()723 uint32_t TJSONProtocol::skipJSONWhitespace() {
724 return skipWhitespace(reader_);
725 }
726
727 // Whitespace characters is allowed before or after any
728 // structural characters
readJSONStructuralChar(uint8_t ch)729 uint32_t TJSONProtocol::readJSONStructuralChar(uint8_t ch) {
730 return readStructuralChar(reader_, ch);
731 }
732
733 // Reads 1 byte and verifies that it matches ch.
readJSONSyntaxChar(uint8_t ch)734 uint32_t TJSONProtocol::readJSONSyntaxChar(uint8_t ch) {
735 return readSyntaxChar(reader_, ch);
736 }
737
738 // Decodes the four hex parts of a JSON escaped string character and returns
739 // the character via out. The first two characters must be "00".
readJSONEscapeChar(uint8_t * out)740 uint32_t TJSONProtocol::readJSONEscapeChar(uint8_t* out) {
741 uint8_t b[2];
742 readJSONSyntaxChar(kJSONZeroChar);
743 readJSONSyntaxChar(kJSONZeroChar);
744 b[0] = reader_.read();
745 b[1] = reader_.read();
746 *out = (hexVal(b[0]) << 4) + hexVal(b[1]);
747 return 4;
748 }
749
750 // Decodes a JSON string, including unescaping, and returns the string via str
readJSONString(std::string & str,bool skipContext)751 uint32_t TJSONProtocol::readJSONString(std::string& str, bool skipContext) {
752 uint32_t result = (skipContext ? 0 : context_->read(reader_));
753 result += readJSONSyntaxChar(kJSONStringDelimiter);
754
755 std::string json("\"");
756 uint8_t ch;
757 str.clear();
758 while (true) {
759 ch = reader_.read();
760 ++result;
761 if (ch == kJSONStringDelimiter) {
762 break;
763 }
764 if (ch == kJSONBackslash) {
765 ch = reader_.read();
766 ++result;
767 if (ch == kJSONEscapeChar) {
768 if (allowDecodeUTF8_) {
769 json += "\\u";
770 continue;
771 } else {
772 result += readJSONEscapeChar(&ch);
773 }
774 } else {
775 size_t pos = kEscapeChars.find(ch);
776 if (pos == std::string::npos) {
777 throw TProtocolException(
778 TProtocolException::INVALID_DATA,
779 "Expected control char, got '" +
780 std::string((const char*)&ch, 1) + "'.");
781 }
782 if (allowDecodeUTF8_) {
783 json += "\\";
784 json += kEscapeChars[pos];
785 continue;
786 } else {
787 ch = kEscapeCharVals[pos];
788 }
789 }
790 }
791
792 if (allowDecodeUTF8_) {
793 json += ch;
794 } else {
795 str += ch;
796 }
797 }
798
799 if (allowDecodeUTF8_) {
800 json += "\"";
801 folly::dynamic parsed = folly::parseJson(json);
802 str += parsed.getString();
803 }
804
805 return result;
806 }
807
808 // Reads a block of base64 characters, decoding it, and returns via str
readJSONBase64(std::string & str)809 uint32_t TJSONProtocol::readJSONBase64(std::string& str) {
810 std::string tmp;
811 uint32_t result = readJSONString(tmp);
812 uint8_t* b = (uint8_t*)tmp.c_str();
813 uint32_t len = tmp.length();
814 str.clear();
815 while (len >= 4) {
816 base64_decode(b, 4);
817 str.append((const char*)b, 3);
818 b += 4;
819 len -= 4;
820 }
821 // Don't decode if we hit the end or got a single leftover byte (invalid
822 // base64 but legal for skip of regular string type)
823 if (len > 1) {
824 base64_decode(b, len);
825 str.append((const char*)b, len - 1);
826 }
827 return result;
828 }
829
830 // Reads a sequence of characters, stopping at the first one that is not
831 // a valid JSON numeric character.
readJSONNumericChars(std::string & str)832 uint32_t TJSONProtocol::readJSONNumericChars(std::string& str) {
833 uint32_t result = 0;
834 str.clear();
835 while (reader_.canPeek()) {
836 uint8_t ch = reader_.peek();
837 if (!isJSONNumeric(ch)) {
838 break;
839 }
840 reader_.read();
841 str += ch;
842 ++result;
843 }
844 return result;
845 }
846
readJSONBool(bool & value)847 uint32_t TJSONProtocol::readJSONBool(bool& value) {
848 uint32_t result = context_->read(reader_);
849
850 if (context_->escapeNum()) {
851 result += readJSONSyntaxChar(kJSONStringDelimiter);
852 }
853
854 uint8_t ch = reader_.read();
855 ++result;
856
857 if (ch == kJSONTrue.at(0)) {
858 for (size_t i = 1; i < kJSONTrue.length(); ++i) {
859 result += readJSONSyntaxChar(kJSONTrue.at(i));
860 }
861 value = true;
862
863 } else if (ch == kJSONFalse.at(0)) {
864 for (size_t i = 1; i < kJSONFalse.length(); ++i) {
865 result += readJSONSyntaxChar(kJSONFalse.at(i));
866 }
867 value = false;
868
869 } else {
870 throw TProtocolException(
871 TProtocolException::INVALID_DATA,
872 "Expected 't' or 'f'; got '" + std::string((char*)&ch, 1) + "'.");
873 }
874
875 if (context_->escapeNum()) {
876 result += readJSONSyntaxChar(kJSONStringDelimiter);
877 }
878
879 return result;
880 }
881
882 // Reads a sequence of characters and assembles them into a number,
883 // returning them via num
884 template <typename NumberType>
readJSONInteger(NumberType & num)885 uint32_t TJSONProtocol::readJSONInteger(NumberType& num) {
886 uint32_t result = context_->read(reader_);
887 if (context_->escapeNum()) {
888 result += readJSONSyntaxChar(kJSONStringDelimiter);
889 }
890 std::string str;
891 result += readJSONNumericChars(str);
892 try {
893 num = folly::to<NumberType>(str);
894 } catch (const std::exception&) {
895 throw TProtocolException(
896 TProtocolException::INVALID_DATA,
897 "Expected numeric value; got \"" + str + "\"");
898 }
899 if (context_->escapeNum()) {
900 result += readJSONSyntaxChar(kJSONStringDelimiter);
901 }
902 return result;
903 }
904
905 // Reads a JSON number or string and interprets it as a double.
906 template <typename NumberType>
readJSONDouble(NumberType & num)907 uint32_t TJSONProtocol::readJSONDouble(NumberType& num) {
908 uint32_t result = context_->read(reader_);
909 std::string str;
910 if (reader_.peek() == kJSONStringDelimiter) {
911 result += readJSONString(str, true);
912 // Check for NaN, Infinity and -Infinity
913 if (str == kThriftNan) {
914 num = HUGE_VAL / HUGE_VAL; // generates NaN
915 } else if (str == kThriftNegativeNan) {
916 num = -NAN;
917 } else if (str == kThriftInfinity) {
918 num = HUGE_VAL;
919 } else if (str == kThriftNegativeInfinity) {
920 num = -HUGE_VAL;
921 } else {
922 if (!context_->escapeNum()) {
923 // Throw exception -- we should not be in a string in this case
924 throw TProtocolException(
925 TProtocolException::INVALID_DATA,
926 "Numeric data unexpectedly quoted");
927 }
928 try {
929 num = folly::to<NumberType>(str);
930 } catch (const std::exception&) {
931 throw TProtocolException(
932 TProtocolException::INVALID_DATA,
933 "Expected numeric value; got \"" + str + "\"");
934 }
935 }
936 } else {
937 if (context_->escapeNum()) {
938 // This will throw - we should have had a quote if escapeNum == true
939 readJSONSyntaxChar(kJSONStringDelimiter);
940 }
941 result += readJSONNumericChars(str);
942 try {
943 num = folly::to<NumberType>(str);
944 } catch (const std::exception&) {
945 throw TProtocolException(
946 TProtocolException::INVALID_DATA,
947 "Expected numeric value; got \"" + str + "\"");
948 }
949 }
950 return result;
951 }
952
readJSONObjectStart()953 uint32_t TJSONProtocol::readJSONObjectStart() {
954 uint32_t result = context_->read(reader_);
955 result += readJSONStructuralChar(kJSONObjectStart);
956 pushContext(std::shared_ptr<TJSONContext>(new JSONPairContext()));
957 return result;
958 }
959
readJSONObjectEnd()960 uint32_t TJSONProtocol::readJSONObjectEnd() {
961 uint32_t result = readJSONStructuralChar(kJSONObjectEnd);
962 popContext();
963 return result;
964 }
965
readJSONArrayStart()966 uint32_t TJSONProtocol::readJSONArrayStart() {
967 uint32_t result = context_->read(reader_);
968 result += readJSONStructuralChar(kJSONArrayStart);
969 pushContext(std::shared_ptr<TJSONContext>(new JSONListContext()));
970 return result;
971 }
972
readJSONArrayEnd()973 uint32_t TJSONProtocol::readJSONArrayEnd() {
974 uint32_t result = readJSONStructuralChar(kJSONArrayEnd);
975 popContext();
976 return result;
977 }
978
readMessageBegin(std::string & name,TMessageType & messageType,int32_t & seqid)979 uint32_t TJSONProtocol::readMessageBegin(
980 std::string& name, TMessageType& messageType, int32_t& seqid) {
981 uint32_t result = readJSONArrayStart();
982 uint64_t tmpVal = 0;
983 result += readJSONInteger(tmpVal);
984 if (tmpVal != kThriftVersion1) {
985 throw TProtocolException(
986 TProtocolException::BAD_VERSION, "Message contained bad version.");
987 }
988 result += readJSONString(name);
989 result += readJSONInteger(tmpVal);
990 messageType = (TMessageType)tmpVal;
991 result += readJSONInteger(tmpVal);
992 seqid = tmpVal;
993 return result;
994 }
995
readMessageEnd()996 uint32_t TJSONProtocol::readMessageEnd() {
997 return readJSONArrayEnd();
998 }
999
readStructBegin(std::string &)1000 uint32_t TJSONProtocol::readStructBegin(std::string& /*name*/) {
1001 return readJSONObjectStart();
1002 }
1003
readStructEnd()1004 uint32_t TJSONProtocol::readStructEnd() {
1005 return readJSONObjectEnd();
1006 }
1007
readFieldBegin(std::string &,TType & fieldType,int16_t & fieldId)1008 uint32_t TJSONProtocol::readFieldBegin(
1009 std::string& /*name*/, TType& fieldType, int16_t& fieldId) {
1010 uint32_t result = 0;
1011 result += skipJSONWhitespace();
1012 // Check if we hit the end of the list
1013 uint8_t ch = reader_.peek();
1014 if (ch == kJSONObjectEnd) {
1015 fieldType = apache::thrift::protocol::T_STOP;
1016 } else {
1017 uint64_t tmpVal = 0;
1018 std::string tmpStr;
1019 result += readJSONInteger(tmpVal);
1020 fieldId = tmpVal;
1021 result += readJSONObjectStart();
1022 result += readJSONString(tmpStr);
1023 fieldType = getTypeIDForTypeName(tmpStr);
1024 }
1025 return result;
1026 }
1027
readFieldEnd()1028 uint32_t TJSONProtocol::readFieldEnd() {
1029 return readJSONObjectEnd();
1030 }
1031
readMapBegin(TType & keyType,TType & valType,uint32_t & size,bool & sizeUnknown)1032 uint32_t TJSONProtocol::readMapBegin(
1033 TType& keyType, TType& valType, uint32_t& size, bool& sizeUnknown) {
1034 uint64_t tmpVal = 0;
1035 std::string tmpStr;
1036 uint32_t result = readJSONArrayStart();
1037 result += readJSONString(tmpStr);
1038 keyType = getTypeIDForTypeName(tmpStr);
1039 result += readJSONString(tmpStr);
1040 valType = getTypeIDForTypeName(tmpStr);
1041 result += readJSONInteger(tmpVal);
1042 size = tmpVal;
1043 result += readJSONObjectStart();
1044 sizeUnknown = false;
1045 return result;
1046 }
1047
readMapEnd()1048 uint32_t TJSONProtocol::readMapEnd() {
1049 return readJSONObjectEnd() + readJSONArrayEnd();
1050 }
1051
readListBegin(TType & elemType,uint32_t & size,bool & sizeUnknown)1052 uint32_t TJSONProtocol::readListBegin(
1053 TType& elemType, uint32_t& size, bool& sizeUnknown) {
1054 uint64_t tmpVal = 0;
1055 std::string tmpStr;
1056 uint32_t result = readJSONArrayStart();
1057 result += readJSONString(tmpStr);
1058 elemType = getTypeIDForTypeName(tmpStr);
1059 result += readJSONInteger(tmpVal);
1060 size = tmpVal;
1061 sizeUnknown = false;
1062 return result;
1063 }
1064
readListEnd()1065 uint32_t TJSONProtocol::readListEnd() {
1066 return readJSONArrayEnd();
1067 }
1068
readSetBegin(TType & elemType,uint32_t & size,bool & sizeUnknown)1069 uint32_t TJSONProtocol::readSetBegin(
1070 TType& elemType, uint32_t& size, bool& sizeUnknown) {
1071 uint64_t tmpVal = 0;
1072 std::string tmpStr;
1073 uint32_t result = readJSONArrayStart();
1074 result += readJSONString(tmpStr);
1075 elemType = getTypeIDForTypeName(tmpStr);
1076 result += readJSONInteger(tmpVal);
1077 size = tmpVal;
1078 sizeUnknown = false;
1079 return result;
1080 }
1081
readSetEnd()1082 uint32_t TJSONProtocol::readSetEnd() {
1083 return readJSONArrayEnd();
1084 }
1085
readBool(bool & value)1086 uint32_t TJSONProtocol::readBool(bool& value) {
1087 return readJSONInteger(value);
1088 }
1089
1090 // readByte() must be handled properly because folly::to sees int8_t
1091 // as a text type instead of an integer type
readByte(int8_t & byte)1092 uint32_t TJSONProtocol::readByte(int8_t& byte) {
1093 int16_t tmp = (int16_t)byte;
1094 uint32_t result = readJSONInteger(tmp);
1095
1096 if (tmp < -128 || tmp > 127) {
1097 throw TProtocolException(
1098 TProtocolException::INVALID_DATA,
1099 folly::to<std::string>("Expected numeric value; got \"", tmp, "\""));
1100 }
1101
1102 byte = (int8_t)tmp;
1103 return result;
1104 }
1105
readI16(int16_t & i16)1106 uint32_t TJSONProtocol::readI16(int16_t& i16) {
1107 return readJSONInteger(i16);
1108 }
1109
readI32(int32_t & i32)1110 uint32_t TJSONProtocol::readI32(int32_t& i32) {
1111 return readJSONInteger(i32);
1112 }
1113
readI64(int64_t & i64)1114 uint32_t TJSONProtocol::readI64(int64_t& i64) {
1115 return readJSONInteger(i64);
1116 }
1117
readDouble(double & dub)1118 uint32_t TJSONProtocol::readDouble(double& dub) {
1119 return readJSONDouble(dub);
1120 }
1121
readFloat(float & flt)1122 uint32_t TJSONProtocol::readFloat(float& flt) {
1123 return readJSONDouble(flt);
1124 }
1125
readString(std::string & str)1126 uint32_t TJSONProtocol::readString(std::string& str) {
1127 return readJSONString(str);
1128 }
1129
readBinary(std::string & str)1130 uint32_t TJSONProtocol::readBinary(std::string& str) {
1131 return readJSONBase64(str);
1132 }
1133
1134 } // namespace protocol
1135 } // namespace thrift
1136 } // namespace apache
1137