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