blob: 6e4e8ef0db6a5ac966a951929d0125a65b68d9b9 [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
David Reissdb0ea152008-02-18 01:49:37 +000019
Roger Meier4285ba22013-06-10 21:17:23 +020020#include <thrift/protocol/TJSONProtocol.h>
David Reissdb0ea152008-02-18 01:49:37 +000021
Jim King1654fe92016-06-19 19:46:01 -040022#include <boost/locale.hpp>
Jim King1654fe92016-06-19 19:46:01 -040023
24#include <cmath>
Konrad Grochowski12b06e42015-02-21 13:48:56 +010025#include <limits>
26#include <locale>
27#include <sstream>
Jim King1654fe92016-06-19 19:46:01 -040028#include <stdexcept>
Konrad Grochowski12b06e42015-02-21 13:48:56 +010029
Roger Meier4285ba22013-06-10 21:17:23 +020030#include <thrift/protocol/TBase64Utils.h>
Roger Meier49ff8b12012-04-13 09:12:31 +000031#include <thrift/transport/TTransportException.h>
Jim Apple117a5cc2017-03-29 20:39:36 -070032#include <thrift/TToString.h>
David Reissdb0ea152008-02-18 01:49:37 +000033
T Jake Lucianib5e62212009-01-31 22:36:20 +000034using namespace apache::thrift::transport;
David Reissdb0ea152008-02-18 01:49:37 +000035
Konrad Grochowski16a23a62014-11-13 15:33:38 +010036namespace apache {
37namespace thrift {
38namespace protocol {
David Reissdb0ea152008-02-18 01:49:37 +000039
40// Static data
41
42static const uint8_t kJSONObjectStart = '{';
43static const uint8_t kJSONObjectEnd = '}';
44static const uint8_t kJSONArrayStart = '[';
45static const uint8_t kJSONArrayEnd = ']';
David Reissdb0ea152008-02-18 01:49:37 +000046static const uint8_t kJSONPairSeparator = ':';
47static const uint8_t kJSONElemSeparator = ',';
48static const uint8_t kJSONBackslash = '\\';
49static const uint8_t kJSONStringDelimiter = '"';
David Reissdb0ea152008-02-18 01:49:37 +000050static const uint8_t kJSONEscapeChar = 'u';
51
52static const std::string kJSONEscapePrefix("\\u00");
53
David Reiss6713e1b2009-01-15 23:56:19 +000054static const uint32_t kThriftVersion1 = 1;
David Reissdb0ea152008-02-18 01:49:37 +000055
56static const std::string kThriftNan("NaN");
57static const std::string kThriftInfinity("Infinity");
58static const std::string kThriftNegativeInfinity("-Infinity");
59
60static const std::string kTypeNameBool("tf");
61static const std::string kTypeNameByte("i8");
62static const std::string kTypeNameI16("i16");
63static const std::string kTypeNameI32("i32");
64static const std::string kTypeNameI64("i64");
65static const std::string kTypeNameDouble("dbl");
66static const std::string kTypeNameStruct("rec");
67static const std::string kTypeNameString("str");
68static const std::string kTypeNameMap("map");
69static const std::string kTypeNameList("lst");
70static const std::string kTypeNameSet("set");
71
Konrad Grochowski16a23a62014-11-13 15:33:38 +010072static const std::string& getTypeNameForTypeID(TType typeID) {
David Reissdb0ea152008-02-18 01:49:37 +000073 switch (typeID) {
74 case T_BOOL:
75 return kTypeNameBool;
76 case T_BYTE:
77 return kTypeNameByte;
78 case T_I16:
79 return kTypeNameI16;
80 case T_I32:
81 return kTypeNameI32;
82 case T_I64:
83 return kTypeNameI64;
84 case T_DOUBLE:
85 return kTypeNameDouble;
86 case T_STRING:
87 return kTypeNameString;
88 case T_STRUCT:
89 return kTypeNameStruct;
90 case T_MAP:
91 return kTypeNameMap;
92 case T_SET:
93 return kTypeNameSet;
94 case T_LIST:
95 return kTypeNameList;
96 default:
Konrad Grochowski16a23a62014-11-13 15:33:38 +010097 throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, "Unrecognized type");
David Reissdb0ea152008-02-18 01:49:37 +000098 }
99}
100
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100101static TType getTypeIDForTypeName(const std::string& name) {
David Reissdb0ea152008-02-18 01:49:37 +0000102 TType result = T_STOP; // Sentinel value
David Reiss2c9824c2008-03-02 00:20:47 +0000103 if (name.length() > 1) {
David Reiss1e62ab42008-02-21 22:37:45 +0000104 switch (name[0]) {
105 case 'd':
106 result = T_DOUBLE;
David Reissdb0ea152008-02-18 01:49:37 +0000107 break;
David Reiss1e62ab42008-02-21 22:37:45 +0000108 case 'i':
109 switch (name[1]) {
110 case '8':
111 result = T_BYTE;
112 break;
113 case '1':
114 result = T_I16;
115 break;
116 case '3':
117 result = T_I32;
118 break;
119 case '6':
120 result = T_I64;
121 break;
122 }
David Reissdb0ea152008-02-18 01:49:37 +0000123 break;
David Reiss1e62ab42008-02-21 22:37:45 +0000124 case 'l':
125 result = T_LIST;
David Reissdb0ea152008-02-18 01:49:37 +0000126 break;
David Reiss1e62ab42008-02-21 22:37:45 +0000127 case 'm':
128 result = T_MAP;
129 break;
130 case 'r':
131 result = T_STRUCT;
132 break;
133 case 's':
134 if (name[1] == 't') {
135 result = T_STRING;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100136 } else if (name[1] == 'e') {
David Reiss1e62ab42008-02-21 22:37:45 +0000137 result = T_SET;
138 }
139 break;
140 case 't':
141 result = T_BOOL;
David Reissdb0ea152008-02-18 01:49:37 +0000142 break;
143 }
David Reissdb0ea152008-02-18 01:49:37 +0000144 }
145 if (result == T_STOP) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100146 throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, "Unrecognized type");
David Reissdb0ea152008-02-18 01:49:37 +0000147 }
148 return result;
149}
150
David Reissdb0ea152008-02-18 01:49:37 +0000151// This table describes the handling for the first 0x30 characters
152// 0 : escape using "\u00xx" notation
153// 1 : just output index
154// <other> : escape using "\<other>" notation
155static const uint8_t kJSONCharTable[0x30] = {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100156 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
157 0,
158 0,
159 0,
160 0,
161 0,
162 0,
163 0,
164 0,
165 'b',
166 't',
167 'n',
168 0,
169 'f',
170 'r',
171 0,
172 0, // 0
173 0,
174 0,
175 0,
176 0,
177 0,
178 0,
179 0,
180 0,
181 0,
182 0,
183 0,
184 0,
185 0,
186 0,
187 0,
188 0, // 1
189 1,
190 1,
191 '"',
192 1,
193 1,
194 1,
195 1,
196 1,
197 1,
198 1,
199 1,
200 1,
201 1,
202 1,
203 1,
204 1, // 2
David Reissdb0ea152008-02-18 01:49:37 +0000205};
206
David Reissdb0ea152008-02-18 01:49:37 +0000207// This string's characters must match up with the elements in kEscapeCharVals.
208// I don't have '/' on this list even though it appears on www.json.org --
209// it is not in the RFC
210const static std::string kEscapeChars("\"\\bfnrt");
211
212// The elements of this array must match up with the sequence of characters in
213// kEscapeChars
214const static uint8_t kEscapeCharVals[7] = {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100215 '"',
216 '\\',
217 '\b',
218 '\f',
219 '\n',
220 '\r',
221 '\t',
David Reissdb0ea152008-02-18 01:49:37 +0000222};
223
David Reissdb0ea152008-02-18 01:49:37 +0000224// Static helper functions
225
226// Read 1 character from the transport trans and verify that it is the
227// expected character ch.
228// Throw a protocol exception if it is not.
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100229static uint32_t readSyntaxChar(TJSONProtocol::LookaheadReader& reader, uint8_t ch) {
David Reiss1e62ab42008-02-21 22:37:45 +0000230 uint8_t ch2 = reader.read();
231 if (ch2 != ch) {
David Reissdb0ea152008-02-18 01:49:37 +0000232 throw TProtocolException(TProtocolException::INVALID_DATA,
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100233 "Expected \'" + std::string((char*)&ch, 1) + "\'; got \'"
234 + std::string((char*)&ch2, 1) + "\'.");
David Reissdb0ea152008-02-18 01:49:37 +0000235 }
236 return 1;
237}
238
David Reissdb0ea152008-02-18 01:49:37 +0000239// Return the integer value of a hex character ch.
240// Throw a protocol exception if the character is not [0-9a-f].
241static uint8_t hexVal(uint8_t ch) {
242 if ((ch >= '0') && (ch <= '9')) {
243 return ch - '0';
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100244 } else if ((ch >= 'a') && (ch <= 'f')) {
Bryan Duxbury4a2bc1b2010-11-03 17:57:38 +0000245 return ch - 'a' + 10;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100246 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000247 throw TProtocolException(TProtocolException::INVALID_DATA,
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100248 "Expected hex val ([0-9a-f]); got \'" + std::string((char*)&ch, 1)
249 + "\'.");
David Reissdb0ea152008-02-18 01:49:37 +0000250 }
251}
252
253// Return the hex character representing the integer val. The value is masked
254// to make sure it is in the correct range.
255static uint8_t hexChar(uint8_t val) {
256 val &= 0x0F;
257 if (val < 10) {
258 return val + '0';
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100259 } else {
Bryan Duxbury4a2bc1b2010-11-03 17:57:38 +0000260 return val - 10 + 'a';
David Reissdb0ea152008-02-18 01:49:37 +0000261 }
262}
263
264// Return true if the character ch is in [-+0-9.Ee]; false otherwise
265static bool isJSONNumeric(uint8_t ch) {
266 switch (ch) {
267 case '+':
268 case '-':
269 case '.':
270 case '0':
271 case '1':
272 case '2':
273 case '3':
274 case '4':
275 case '5':
276 case '6':
277 case '7':
278 case '8':
279 case '9':
280 case 'E':
281 case 'e':
282 return true;
283 }
284 return false;
285}
286
Konrad Grochowskia84e1392015-10-16 11:22:10 +0200287// Return true if the code unit is high surrogate
288static bool isHighSurrogate(uint16_t val) {
289 return val >= 0xD800 && val <= 0xDBFF;
290}
291
292// Return true if the code unit is low surrogate
293static bool isLowSurrogate(uint16_t val) {
294 return val >= 0xDC00 && val <= 0xDFFF;
295}
296
David Reissdb0ea152008-02-18 01:49:37 +0000297/**
David Reiss1e62ab42008-02-21 22:37:45 +0000298 * Class to serve as base JSON context and as base class for other context
David Reissdb0ea152008-02-18 01:49:37 +0000299 * implementations
300 */
301class TJSONContext {
302
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100303public:
James E. King IIIf95620d2019-01-28 18:15:13 -0500304 TJSONContext() = default;
David Reissdb0ea152008-02-18 01:49:37 +0000305
James E. King IIIf95620d2019-01-28 18:15:13 -0500306 virtual ~TJSONContext() = default;
David Reissdb0ea152008-02-18 01:49:37 +0000307
308 /**
309 * Write context data to the transport. Default is to do nothing.
310 */
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100311 virtual uint32_t write(TTransport& trans) {
312 (void)trans;
David Reissdb0ea152008-02-18 01:49:37 +0000313 return 0;
314 };
315
316 /**
317 * Read context data from the transport. Default is to do nothing.
318 */
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100319 virtual uint32_t read(TJSONProtocol::LookaheadReader& reader) {
320 (void)reader;
David Reissdb0ea152008-02-18 01:49:37 +0000321 return 0;
322 };
323
324 /**
325 * Return true if numbers need to be escaped as strings in this context.
326 * Default behavior is to return false.
327 */
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100328 virtual bool escapeNum() { return false; }
David Reissdb0ea152008-02-18 01:49:37 +0000329};
330
331// Context class for object member key-value pairs
332class JSONPairContext : public TJSONContext {
333
334public:
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100335 JSONPairContext() : first_(true), colon_(true) {}
David Reissdb0ea152008-02-18 01:49:37 +0000336
Sebastian Zenker042580f2019-01-29 15:48:12 +0100337 uint32_t write(TTransport& trans) override {
David Reissdb0ea152008-02-18 01:49:37 +0000338 if (first_) {
339 first_ = false;
340 colon_ = true;
341 return 0;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100342 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000343 trans.write(colon_ ? &kJSONPairSeparator : &kJSONElemSeparator, 1);
344 colon_ = !colon_;
345 return 1;
346 }
347 }
348
Sebastian Zenker042580f2019-01-29 15:48:12 +0100349 uint32_t read(TJSONProtocol::LookaheadReader& reader) override {
David Reissdb0ea152008-02-18 01:49:37 +0000350 if (first_) {
351 first_ = false;
352 colon_ = true;
353 return 0;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100354 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000355 uint8_t ch = (colon_ ? kJSONPairSeparator : kJSONElemSeparator);
356 colon_ = !colon_;
David Reiss1e62ab42008-02-21 22:37:45 +0000357 return readSyntaxChar(reader, ch);
David Reissdb0ea152008-02-18 01:49:37 +0000358 }
359 }
360
361 // Numbers must be turned into strings if they are the key part of a pair
Sebastian Zenker042580f2019-01-29 15:48:12 +0100362 bool escapeNum() override { return colon_; }
David Reissdb0ea152008-02-18 01:49:37 +0000363
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100364private:
365 bool first_;
366 bool colon_;
David Reissdb0ea152008-02-18 01:49:37 +0000367};
368
369// Context class for lists
370class JSONListContext : public TJSONContext {
371
372public:
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100373 JSONListContext() : first_(true) {}
David Reissdb0ea152008-02-18 01:49:37 +0000374
Sebastian Zenker042580f2019-01-29 15:48:12 +0100375 uint32_t write(TTransport& trans) override {
David Reissdb0ea152008-02-18 01:49:37 +0000376 if (first_) {
377 first_ = false;
378 return 0;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100379 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000380 trans.write(&kJSONElemSeparator, 1);
381 return 1;
382 }
383 }
384
Sebastian Zenker042580f2019-01-29 15:48:12 +0100385 uint32_t read(TJSONProtocol::LookaheadReader& reader) override {
David Reissdb0ea152008-02-18 01:49:37 +0000386 if (first_) {
387 first_ = false;
388 return 0;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100389 } else {
David Reiss1e62ab42008-02-21 22:37:45 +0000390 return readSyntaxChar(reader, kJSONElemSeparator);
David Reissdb0ea152008-02-18 01:49:37 +0000391 }
392 }
393
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100394private:
395 bool first_;
David Reissdb0ea152008-02-18 01:49:37 +0000396};
397
cyy316723a2019-01-05 16:35:14 +0800398TJSONProtocol::TJSONProtocol(std::shared_ptr<TTransport> ptrans)
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100399 : TVirtualProtocol<TJSONProtocol>(ptrans),
400 trans_(ptrans.get()),
401 context_(new TJSONContext()),
402 reader_(*ptrans) {
David Reissdb0ea152008-02-18 01:49:37 +0000403}
404
Sebastian Zenker042580f2019-01-29 15:48:12 +0100405TJSONProtocol::~TJSONProtocol() = default;
David Reissdb0ea152008-02-18 01:49:37 +0000406
cyy316723a2019-01-05 16:35:14 +0800407void TJSONProtocol::pushContext(std::shared_ptr<TJSONContext> c) {
David Reissdb0ea152008-02-18 01:49:37 +0000408 contexts_.push(context_);
409 context_ = c;
410}
411
412void TJSONProtocol::popContext() {
413 context_ = contexts_.top();
414 contexts_.pop();
415}
416
417// Write the character ch as a JSON escape sequence ("\u00xx")
418uint32_t TJSONProtocol::writeJSONEscapeChar(uint8_t ch) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100419 trans_->write((const uint8_t*)kJSONEscapePrefix.c_str(),
Roger Meierb69d24d2012-10-04 18:02:15 +0000420 static_cast<uint32_t>(kJSONEscapePrefix.length()));
David Reissdb0ea152008-02-18 01:49:37 +0000421 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.
429uint32_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;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100435 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000436 trans_->write(&ch, 1);
437 return 1;
438 }
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100439 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000440 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;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100445 } else if (outCh > 1) {
David Reissdb0ea152008-02-18 01:49:37 +0000446 trans_->write(&kJSONBackslash, 1);
447 trans_->write(&outCh, 1);
448 return 2;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100449 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000450 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.
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100457uint32_t TJSONProtocol::writeJSONString(const std::string& str) {
David Reissdb0ea152008-02-18 01:49:37 +0000458 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
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100472uint32_t TJSONProtocol::writeJSONBase64(const std::string& str) {
David Reissdb0ea152008-02-18 01:49:37 +0000473 uint32_t result = context_->write(*trans_);
474 result += 2; // For quotes
475 trans_->write(&kJSONStringDelimiter, 1);
476 uint8_t b[4];
Sebastian Zenker042580f2019-01-29 15:48:12 +0100477 const auto* bytes = (const uint8_t*)str.c_str();
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100478 if (str.length() > (std::numeric_limits<uint32_t>::max)())
Roger Meierb69d24d2012-10-04 18:02:15 +0000479 throw TProtocolException(TProtocolException::SIZE_LIMIT);
Sebastian Zenker042580f2019-01-29 15:48:12 +0100480 auto len = static_cast<uint32_t>(str.length());
David Reissdb0ea152008-02-18 01:49:37 +0000481 while (len >= 3) {
482 // Encode 3 bytes at a time
483 base64_encode(bytes, 3, b);
484 trans_->write(b, 4);
485 result += 4;
486 bytes += 3;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100487 len -= 3;
David Reissdb0ea152008-02-18 01:49:37 +0000488 }
489 if (len) { // Handle remainder
490 base64_encode(bytes, len, b);
491 trans_->write(b, len + 1);
492 result += len + 1;
493 }
494 trans_->write(&kJSONStringDelimiter, 1);
495 return result;
496}
497
498// Convert the given integer type to a JSON number, or a string
499// if the context requires it (eg: key in a map pair).
500template <typename NumberType>
501uint32_t TJSONProtocol::writeJSONInteger(NumberType num) {
502 uint32_t result = context_->write(*trans_);
Jim Apple117a5cc2017-03-29 20:39:36 -0700503 std::string val(to_string(num));
David Reissdb0ea152008-02-18 01:49:37 +0000504 bool escapeNum = context_->escapeNum();
505 if (escapeNum) {
506 trans_->write(&kJSONStringDelimiter, 1);
507 result += 1;
508 }
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100509 if (val.length() > (std::numeric_limits<uint32_t>::max)())
Roger Meierb69d24d2012-10-04 18:02:15 +0000510 throw TProtocolException(TProtocolException::SIZE_LIMIT);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100511 trans_->write((const uint8_t*)val.c_str(), static_cast<uint32_t>(val.length()));
Roger Meierb69d24d2012-10-04 18:02:15 +0000512 result += static_cast<uint32_t>(val.length());
David Reissdb0ea152008-02-18 01:49:37 +0000513 if (escapeNum) {
514 trans_->write(&kJSONStringDelimiter, 1);
515 result += 1;
516 }
517 return result;
518}
519
Konrad Grochowski1f6e3802015-05-18 18:10:06 +0200520namespace {
521std::string doubleToString(double d) {
Konrad Grochowski12b06e42015-02-21 13:48:56 +0100522 std::ostringstream str;
523 str.imbue(std::locale::classic());
James E. King, III7edc8fa2017-01-20 10:11:41 -0500524 const std::streamsize max_digits10 = 2 + std::numeric_limits<double>::digits10;
Wang Yaofu0433d172016-02-15 10:43:09 +0800525 str.precision(max_digits10);
Konrad Grochowski12b06e42015-02-21 13:48:56 +0100526 str << d;
527 return str.str();
528}
529}
530
David Reissdb0ea152008-02-18 01:49:37 +0000531// Convert the given double to a JSON string, which is either the number,
532// "NaN" or "Infinity" or "-Infinity".
533uint32_t TJSONProtocol::writeJSONDouble(double num) {
534 uint32_t result = context_->write(*trans_);
Konrad Grochowski12b06e42015-02-21 13:48:56 +0100535 std::string val;
David Reissdb0ea152008-02-18 01:49:37 +0000536
David Reissdb0ea152008-02-18 01:49:37 +0000537 bool special = false;
cyy64750162019-02-08 13:40:59 +0800538 switch (std::fpclassify(num)) {
Konrad Grochowski12b06e42015-02-21 13:48:56 +0100539 case FP_INFINITE:
cyy64750162019-02-08 13:40:59 +0800540 if (std::signbit(num)) {
Konrad Grochowski12b06e42015-02-21 13:48:56 +0100541 val = kThriftNegativeInfinity;
542 } else {
543 val = kThriftInfinity;
544 }
545 special = true;
546 break;
547 case FP_NAN:
David Reissdb0ea152008-02-18 01:49:37 +0000548 val = kThriftNan;
549 special = true;
550 break;
Konrad Grochowski12b06e42015-02-21 13:48:56 +0100551 default:
552 val = doubleToString(num);
David Reissdb0ea152008-02-18 01:49:37 +0000553 break;
554 }
555
556 bool escapeNum = special || context_->escapeNum();
557 if (escapeNum) {
558 trans_->write(&kJSONStringDelimiter, 1);
559 result += 1;
560 }
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100561 if (val.length() > (std::numeric_limits<uint32_t>::max)())
Roger Meierb69d24d2012-10-04 18:02:15 +0000562 throw TProtocolException(TProtocolException::SIZE_LIMIT);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100563 trans_->write((const uint8_t*)val.c_str(), static_cast<uint32_t>(val.length()));
Roger Meierb69d24d2012-10-04 18:02:15 +0000564 result += static_cast<uint32_t>(val.length());
David Reissdb0ea152008-02-18 01:49:37 +0000565 if (escapeNum) {
566 trans_->write(&kJSONStringDelimiter, 1);
567 result += 1;
568 }
569 return result;
570}
571
572uint32_t TJSONProtocol::writeJSONObjectStart() {
573 uint32_t result = context_->write(*trans_);
574 trans_->write(&kJSONObjectStart, 1);
cyy316723a2019-01-05 16:35:14 +0800575 pushContext(std::shared_ptr<TJSONContext>(new JSONPairContext()));
David Reissdb0ea152008-02-18 01:49:37 +0000576 return result + 1;
577}
578
579uint32_t TJSONProtocol::writeJSONObjectEnd() {
580 popContext();
581 trans_->write(&kJSONObjectEnd, 1);
582 return 1;
583}
584
585uint32_t TJSONProtocol::writeJSONArrayStart() {
586 uint32_t result = context_->write(*trans_);
587 trans_->write(&kJSONArrayStart, 1);
cyy316723a2019-01-05 16:35:14 +0800588 pushContext(std::shared_ptr<TJSONContext>(new JSONListContext()));
David Reissdb0ea152008-02-18 01:49:37 +0000589 return result + 1;
590}
591
592uint32_t TJSONProtocol::writeJSONArrayEnd() {
593 popContext();
594 trans_->write(&kJSONArrayEnd, 1);
595 return 1;
596}
597
598uint32_t TJSONProtocol::writeMessageBegin(const std::string& name,
599 const TMessageType messageType,
600 const int32_t seqid) {
601 uint32_t result = writeJSONArrayStart();
602 result += writeJSONInteger(kThriftVersion1);
603 result += writeJSONString(name);
604 result += writeJSONInteger(messageType);
605 result += writeJSONInteger(seqid);
606 return result;
607}
608
609uint32_t TJSONProtocol::writeMessageEnd() {
610 return writeJSONArrayEnd();
611}
612
David Reiss64120002008-04-29 23:12:24 +0000613uint32_t TJSONProtocol::writeStructBegin(const char* name) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100614 (void)name;
David Reissdb0ea152008-02-18 01:49:37 +0000615 return writeJSONObjectStart();
616}
617
618uint32_t TJSONProtocol::writeStructEnd() {
619 return writeJSONObjectEnd();
620}
621
David Reiss64120002008-04-29 23:12:24 +0000622uint32_t TJSONProtocol::writeFieldBegin(const char* name,
David Reissdb0ea152008-02-18 01:49:37 +0000623 const TType fieldType,
624 const int16_t fieldId) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100625 (void)name;
David Reissdb0ea152008-02-18 01:49:37 +0000626 uint32_t result = writeJSONInteger(fieldId);
627 result += writeJSONObjectStart();
628 result += writeJSONString(getTypeNameForTypeID(fieldType));
629 return result;
630}
631
632uint32_t TJSONProtocol::writeFieldEnd() {
633 return writeJSONObjectEnd();
634}
635
636uint32_t TJSONProtocol::writeFieldStop() {
637 return 0;
638}
639
640uint32_t TJSONProtocol::writeMapBegin(const TType keyType,
641 const TType valType,
642 const uint32_t size) {
643 uint32_t result = writeJSONArrayStart();
644 result += writeJSONString(getTypeNameForTypeID(keyType));
645 result += writeJSONString(getTypeNameForTypeID(valType));
646 result += writeJSONInteger((int64_t)size);
647 result += writeJSONObjectStart();
648 return result;
649}
650
651uint32_t TJSONProtocol::writeMapEnd() {
dtmuller4300b722016-07-15 10:05:43 +0200652 uint32_t result = writeJSONObjectEnd();
653 result += writeJSONArrayEnd();
654 return result;
David Reissdb0ea152008-02-18 01:49:37 +0000655}
656
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100657uint32_t TJSONProtocol::writeListBegin(const TType elemType, const uint32_t size) {
David Reissdb0ea152008-02-18 01:49:37 +0000658 uint32_t result = writeJSONArrayStart();
659 result += writeJSONString(getTypeNameForTypeID(elemType));
660 result += writeJSONInteger((int64_t)size);
661 return result;
662}
663
664uint32_t TJSONProtocol::writeListEnd() {
665 return writeJSONArrayEnd();
666}
667
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100668uint32_t TJSONProtocol::writeSetBegin(const TType elemType, const uint32_t size) {
David Reissdb0ea152008-02-18 01:49:37 +0000669 uint32_t result = writeJSONArrayStart();
670 result += writeJSONString(getTypeNameForTypeID(elemType));
671 result += writeJSONInteger((int64_t)size);
672 return result;
673}
674
675uint32_t TJSONProtocol::writeSetEnd() {
676 return writeJSONArrayEnd();
677}
678
679uint32_t TJSONProtocol::writeBool(const bool value) {
680 return writeJSONInteger(value);
681}
682
683uint32_t TJSONProtocol::writeByte(const int8_t byte) {
Jim Apple117a5cc2017-03-29 20:39:36 -0700684 // writeByte() must be handled specially because to_string sees
David Reissdb0ea152008-02-18 01:49:37 +0000685 // int8_t as a text type instead of an integer type
686 return writeJSONInteger((int16_t)byte);
687}
688
689uint32_t TJSONProtocol::writeI16(const int16_t i16) {
690 return writeJSONInteger(i16);
691}
692
693uint32_t TJSONProtocol::writeI32(const int32_t i32) {
694 return writeJSONInteger(i32);
695}
696
697uint32_t TJSONProtocol::writeI64(const int64_t i64) {
698 return writeJSONInteger(i64);
699}
700
701uint32_t TJSONProtocol::writeDouble(const double dub) {
702 return writeJSONDouble(dub);
703}
704
705uint32_t TJSONProtocol::writeString(const std::string& str) {
706 return writeJSONString(str);
707}
708
709uint32_t TJSONProtocol::writeBinary(const std::string& str) {
710 return writeJSONBase64(str);
711}
712
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100713/**
714 * Reading functions
715 */
David Reissdb0ea152008-02-18 01:49:37 +0000716
David Reiss1e62ab42008-02-21 22:37:45 +0000717// Reads 1 byte and verifies that it matches ch.
David Reissdb0ea152008-02-18 01:49:37 +0000718uint32_t TJSONProtocol::readJSONSyntaxChar(uint8_t ch) {
David Reiss1e62ab42008-02-21 22:37:45 +0000719 return readSyntaxChar(reader_, ch);
David Reissdb0ea152008-02-18 01:49:37 +0000720}
721
722// Decodes the four hex parts of a JSON escaped string character and returns
Konrad Grochowskia84e1392015-10-16 11:22:10 +0200723// the UTF-16 code unit via out.
724uint32_t TJSONProtocol::readJSONEscapeChar(uint16_t* out) {
725 uint8_t b[4];
David Reiss1e62ab42008-02-21 22:37:45 +0000726 b[0] = reader_.read();
727 b[1] = reader_.read();
Konrad Grochowskia84e1392015-10-16 11:22:10 +0200728 b[2] = reader_.read();
729 b[3] = reader_.read();
730
731 *out = (hexVal(b[0]) << 12)
732 + (hexVal(b[1]) << 8) + (hexVal(b[2]) << 4) + hexVal(b[3]);
733
David Reissdb0ea152008-02-18 01:49:37 +0000734 return 4;
735}
736
737// Decodes a JSON string, including unescaping, and returns the string via str
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100738uint32_t TJSONProtocol::readJSONString(std::string& str, bool skipContext) {
David Reiss1e62ab42008-02-21 22:37:45 +0000739 uint32_t result = (skipContext ? 0 : context_->read(reader_));
David Reissdb0ea152008-02-18 01:49:37 +0000740 result += readJSONSyntaxChar(kJSONStringDelimiter);
Konrad Grochowskia84e1392015-10-16 11:22:10 +0200741 std::vector<uint16_t> codeunits;
David Reiss1e62ab42008-02-21 22:37:45 +0000742 uint8_t ch;
David Reiss91630732008-02-28 21:11:39 +0000743 str.clear();
David Reissdb0ea152008-02-18 01:49:37 +0000744 while (true) {
David Reiss1e62ab42008-02-21 22:37:45 +0000745 ch = reader_.read();
746 ++result;
747 if (ch == kJSONStringDelimiter) {
David Reissdb0ea152008-02-18 01:49:37 +0000748 break;
749 }
David Reiss1e62ab42008-02-21 22:37:45 +0000750 if (ch == kJSONBackslash) {
751 ch = reader_.read();
752 ++result;
753 if (ch == kJSONEscapeChar) {
Konrad Grochowskia84e1392015-10-16 11:22:10 +0200754 uint16_t cp;
755 result += readJSONEscapeChar(&cp);
756 if (isHighSurrogate(cp)) {
757 codeunits.push_back(cp);
758 } else {
759 if (isLowSurrogate(cp)
760 && codeunits.empty()) {
761 throw TProtocolException(TProtocolException::INVALID_DATA,
762 "Missing UTF-16 high surrogate pair.");
763 }
764 codeunits.push_back(cp);
765 codeunits.push_back(0);
766 str += boost::locale::conv::utf_to_utf<char>(codeunits.data());
767 codeunits.clear();
768 }
769 continue;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100770 } else {
David Reiss1e62ab42008-02-21 22:37:45 +0000771 size_t pos = kEscapeChars.find(ch);
James E. King, III43f4bf22017-10-28 12:54:02 -0400772 if (pos == kEscapeChars.npos) {
David Reissdb0ea152008-02-18 01:49:37 +0000773 throw TProtocolException(TProtocolException::INVALID_DATA,
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100774 "Expected control char, got '" + std::string((const char*)&ch, 1)
775 + "'.");
David Reissdb0ea152008-02-18 01:49:37 +0000776 }
David Reiss1e62ab42008-02-21 22:37:45 +0000777 ch = kEscapeCharVals[pos];
David Reissdb0ea152008-02-18 01:49:37 +0000778 }
779 }
Konrad Grochowskia84e1392015-10-16 11:22:10 +0200780 if (!codeunits.empty()) {
781 throw TProtocolException(TProtocolException::INVALID_DATA,
782 "Missing UTF-16 low surrogate pair.");
783 }
David Reiss1e62ab42008-02-21 22:37:45 +0000784 str += ch;
David Reissdb0ea152008-02-18 01:49:37 +0000785 }
Konrad Grochowskia84e1392015-10-16 11:22:10 +0200786
787 if (!codeunits.empty()) {
788 throw TProtocolException(TProtocolException::INVALID_DATA,
789 "Missing UTF-16 low surrogate pair.");
790 }
David Reissdb0ea152008-02-18 01:49:37 +0000791 return result;
792}
793
794// Reads a block of base64 characters, decoding it, and returns via str
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100795uint32_t TJSONProtocol::readJSONBase64(std::string& str) {
David Reissdb0ea152008-02-18 01:49:37 +0000796 std::string tmp;
797 uint32_t result = readJSONString(tmp);
Sebastian Zenker042580f2019-01-29 15:48:12 +0100798 auto* b = (uint8_t*)tmp.c_str();
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100799 if (tmp.length() > (std::numeric_limits<uint32_t>::max)())
Roger Meierb69d24d2012-10-04 18:02:15 +0000800 throw TProtocolException(TProtocolException::SIZE_LIMIT);
Sebastian Zenker042580f2019-01-29 15:48:12 +0100801 auto len = static_cast<uint32_t>(tmp.length());
David Reiss91630732008-02-28 21:11:39 +0000802 str.clear();
Nobuaki Sukegawaa1754372015-10-10 10:44:07 +0900803 // Ignore padding
Nobuaki Sukegawadfb68962015-12-09 22:09:26 +0900804 if (len >= 2) {
805 uint32_t bound = len - 2;
806 for (uint32_t i = len - 1; i >= bound && b[i] == '='; --i) {
807 --len;
808 }
Nobuaki Sukegawaa1754372015-10-10 10:44:07 +0900809 }
David Reissdb0ea152008-02-18 01:49:37 +0000810 while (len >= 4) {
811 base64_decode(b, 4);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100812 str.append((const char*)b, 3);
David Reissdb0ea152008-02-18 01:49:37 +0000813 b += 4;
814 len -= 4;
815 }
816 // Don't decode if we hit the end or got a single leftover byte (invalid
817 // base64 but legal for skip of regular string type)
818 if (len > 1) {
819 base64_decode(b, len);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100820 str.append((const char*)b, len - 1);
David Reissdb0ea152008-02-18 01:49:37 +0000821 }
822 return result;
823}
824
825// Reads a sequence of characters, stopping at the first one that is not
826// a valid JSON numeric character.
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100827uint32_t TJSONProtocol::readJSONNumericChars(std::string& str) {
David Reissdb0ea152008-02-18 01:49:37 +0000828 uint32_t result = 0;
David Reiss91630732008-02-28 21:11:39 +0000829 str.clear();
David Reissdb0ea152008-02-18 01:49:37 +0000830 while (true) {
David Reiss1e62ab42008-02-21 22:37:45 +0000831 uint8_t ch = reader_.peek();
David Reissdb0ea152008-02-18 01:49:37 +0000832 if (!isJSONNumeric(ch)) {
833 break;
834 }
David Reiss1e62ab42008-02-21 22:37:45 +0000835 reader_.read();
David Reissdb0ea152008-02-18 01:49:37 +0000836 str += ch;
837 ++result;
838 }
839 return result;
840}
841
Jim Apple117a5cc2017-03-29 20:39:36 -0700842namespace {
843template <typename T>
844T fromString(const std::string& s) {
845 T t;
846 std::istringstream str(s);
847 str.imbue(std::locale::classic());
848 str >> t;
849 if (str.bad() || !str.eof())
850 throw std::runtime_error(s);
851 return t;
852}
853}
854
David Reissdb0ea152008-02-18 01:49:37 +0000855// Reads a sequence of characters and assembles them into a number,
856// returning them via num
857template <typename NumberType>
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100858uint32_t TJSONProtocol::readJSONInteger(NumberType& num) {
David Reiss1e62ab42008-02-21 22:37:45 +0000859 uint32_t result = context_->read(reader_);
David Reissdb0ea152008-02-18 01:49:37 +0000860 if (context_->escapeNum()) {
861 result += readJSONSyntaxChar(kJSONStringDelimiter);
862 }
863 std::string str;
864 result += readJSONNumericChars(str);
865 try {
Jim Apple117a5cc2017-03-29 20:39:36 -0700866 num = fromString<NumberType>(str);
867 } catch (const std::runtime_error&) {
Claudius Heine8f11f522015-07-01 10:35:38 +0200868 throw TProtocolException(TProtocolException::INVALID_DATA,
Jim Apple117a5cc2017-03-29 20:39:36 -0700869 "Expected numeric value; got \"" + str + "\"");
David Reissdb0ea152008-02-18 01:49:37 +0000870 }
871 if (context_->escapeNum()) {
872 result += readJSONSyntaxChar(kJSONStringDelimiter);
873 }
874 return result;
875}
876
877// Reads a JSON number or string and interprets it as a double.
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100878uint32_t TJSONProtocol::readJSONDouble(double& num) {
David Reiss1e62ab42008-02-21 22:37:45 +0000879 uint32_t result = context_->read(reader_);
David Reissdb0ea152008-02-18 01:49:37 +0000880 std::string str;
David Reiss1e62ab42008-02-21 22:37:45 +0000881 if (reader_.peek() == kJSONStringDelimiter) {
David Reissdb0ea152008-02-18 01:49:37 +0000882 result += readJSONString(str, true);
883 // Check for NaN, Infinity and -Infinity
884 if (str == kThriftNan) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100885 num = HUGE_VAL / HUGE_VAL; // generates NaN
886 } else if (str == kThriftInfinity) {
David Reissdb0ea152008-02-18 01:49:37 +0000887 num = HUGE_VAL;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100888 } else if (str == kThriftNegativeInfinity) {
David Reissdb0ea152008-02-18 01:49:37 +0000889 num = -HUGE_VAL;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100890 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000891 if (!context_->escapeNum()) {
892 // Throw exception -- we should not be in a string in this case
Claudius Heine8f11f522015-07-01 10:35:38 +0200893 throw TProtocolException(TProtocolException::INVALID_DATA,
David Reissdb0ea152008-02-18 01:49:37 +0000894 "Numeric data unexpectedly quoted");
895 }
896 try {
Jim Apple117a5cc2017-03-29 20:39:36 -0700897 num = fromString<double>(str);
James E. King III278528c2019-01-11 12:17:44 -0500898 } catch (const std::runtime_error&) {
Claudius Heine8f11f522015-07-01 10:35:38 +0200899 throw TProtocolException(TProtocolException::INVALID_DATA,
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100900 "Expected numeric value; got \"" + str + "\"");
David Reissdb0ea152008-02-18 01:49:37 +0000901 }
902 }
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100903 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000904 if (context_->escapeNum()) {
905 // This will throw - we should have had a quote if escapeNum == true
906 readJSONSyntaxChar(kJSONStringDelimiter);
907 }
908 result += readJSONNumericChars(str);
909 try {
Jim Apple117a5cc2017-03-29 20:39:36 -0700910 num = fromString<double>(str);
James E. King III278528c2019-01-11 12:17:44 -0500911 } catch (const std::runtime_error&) {
Claudius Heine8f11f522015-07-01 10:35:38 +0200912 throw TProtocolException(TProtocolException::INVALID_DATA,
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100913 "Expected numeric value; got \"" + str + "\"");
David Reissdb0ea152008-02-18 01:49:37 +0000914 }
915 }
916 return result;
917}
918
919uint32_t TJSONProtocol::readJSONObjectStart() {
David Reiss1e62ab42008-02-21 22:37:45 +0000920 uint32_t result = context_->read(reader_);
David Reissdb0ea152008-02-18 01:49:37 +0000921 result += readJSONSyntaxChar(kJSONObjectStart);
cyy316723a2019-01-05 16:35:14 +0800922 pushContext(std::shared_ptr<TJSONContext>(new JSONPairContext()));
David Reissdb0ea152008-02-18 01:49:37 +0000923 return result;
924}
925
926uint32_t TJSONProtocol::readJSONObjectEnd() {
927 uint32_t result = readJSONSyntaxChar(kJSONObjectEnd);
928 popContext();
929 return result;
930}
931
932uint32_t TJSONProtocol::readJSONArrayStart() {
David Reiss1e62ab42008-02-21 22:37:45 +0000933 uint32_t result = context_->read(reader_);
David Reissdb0ea152008-02-18 01:49:37 +0000934 result += readJSONSyntaxChar(kJSONArrayStart);
cyy316723a2019-01-05 16:35:14 +0800935 pushContext(std::shared_ptr<TJSONContext>(new JSONListContext()));
David Reissdb0ea152008-02-18 01:49:37 +0000936 return result;
937}
938
939uint32_t TJSONProtocol::readJSONArrayEnd() {
940 uint32_t result = readJSONSyntaxChar(kJSONArrayEnd);
941 popContext();
942 return result;
943}
944
945uint32_t TJSONProtocol::readMessageBegin(std::string& name,
946 TMessageType& messageType,
947 int32_t& seqid) {
948 uint32_t result = readJSONArrayStart();
James E. King III973c8552019-01-30 20:11:15 -0500949 int64_t tmpVal = 0;
David Reissdb0ea152008-02-18 01:49:37 +0000950 result += readJSONInteger(tmpVal);
951 if (tmpVal != kThriftVersion1) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100952 throw TProtocolException(TProtocolException::BAD_VERSION, "Message contained bad version.");
David Reissdb0ea152008-02-18 01:49:37 +0000953 }
954 result += readJSONString(name);
955 result += readJSONInteger(tmpVal);
956 messageType = (TMessageType)tmpVal;
957 result += readJSONInteger(tmpVal);
James E. King III973c8552019-01-30 20:11:15 -0500958 if (tmpVal > (std::numeric_limits<int32_t>::max)() ||
959 tmpVal < (std::numeric_limits<int32_t>::min)())
960 throw TProtocolException(TProtocolException::INVALID_DATA, "sequence id is not int32_t");
Roger Meierb69d24d2012-10-04 18:02:15 +0000961 seqid = static_cast<int32_t>(tmpVal);
David Reissdb0ea152008-02-18 01:49:37 +0000962 return result;
963}
964
965uint32_t TJSONProtocol::readMessageEnd() {
966 return readJSONArrayEnd();
967}
968
969uint32_t TJSONProtocol::readStructBegin(std::string& name) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100970 (void)name;
David Reissdb0ea152008-02-18 01:49:37 +0000971 return readJSONObjectStart();
972}
973
974uint32_t TJSONProtocol::readStructEnd() {
975 return readJSONObjectEnd();
976}
977
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100978uint32_t TJSONProtocol::readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId) {
979 (void)name;
David Reissdb0ea152008-02-18 01:49:37 +0000980 uint32_t result = 0;
David Reiss1e62ab42008-02-21 22:37:45 +0000981 // Check if we hit the end of the list
982 uint8_t ch = reader_.peek();
983 if (ch == kJSONObjectEnd) {
T Jake Lucianib5e62212009-01-31 22:36:20 +0000984 fieldType = apache::thrift::protocol::T_STOP;
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100985 } else {
David Reissdb0ea152008-02-18 01:49:37 +0000986 uint64_t tmpVal = 0;
987 std::string tmpStr;
988 result += readJSONInteger(tmpVal);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100989 if (tmpVal > static_cast<uint32_t>((std::numeric_limits<int16_t>::max)()))
Roger Meierb69d24d2012-10-04 18:02:15 +0000990 throw TProtocolException(TProtocolException::SIZE_LIMIT);
991 fieldId = static_cast<int16_t>(tmpVal);
David Reissdb0ea152008-02-18 01:49:37 +0000992 result += readJSONObjectStart();
993 result += readJSONString(tmpStr);
994 fieldType = getTypeIDForTypeName(tmpStr);
995 }
996 return result;
997}
998
999uint32_t TJSONProtocol::readFieldEnd() {
1000 return readJSONObjectEnd();
1001}
1002
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001003uint32_t TJSONProtocol::readMapBegin(TType& keyType, TType& valType, uint32_t& size) {
David Reissdb0ea152008-02-18 01:49:37 +00001004 uint64_t tmpVal = 0;
1005 std::string tmpStr;
1006 uint32_t result = readJSONArrayStart();
1007 result += readJSONString(tmpStr);
1008 keyType = getTypeIDForTypeName(tmpStr);
1009 result += readJSONString(tmpStr);
1010 valType = getTypeIDForTypeName(tmpStr);
1011 result += readJSONInteger(tmpVal);
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001012 if (tmpVal > (std::numeric_limits<uint32_t>::max)())
Roger Meierb69d24d2012-10-04 18:02:15 +00001013 throw TProtocolException(TProtocolException::SIZE_LIMIT);
1014 size = static_cast<uint32_t>(tmpVal);
David Reissdb0ea152008-02-18 01:49:37 +00001015 result += readJSONObjectStart();
zeshuai00786352b42020-06-15 17:00:33 +08001016
1017 TMap map(keyType, valType, size);
1018 checkReadBytesAvailable(map);
1019
David Reissdb0ea152008-02-18 01:49:37 +00001020 return result;
1021}
1022
1023uint32_t TJSONProtocol::readMapEnd() {
dtmuller4300b722016-07-15 10:05:43 +02001024 uint32_t result = readJSONObjectEnd();
1025 result += readJSONArrayEnd();
1026 return result;
David Reissdb0ea152008-02-18 01:49:37 +00001027}
1028
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001029uint32_t TJSONProtocol::readListBegin(TType& elemType, uint32_t& size) {
David Reissdb0ea152008-02-18 01:49:37 +00001030 uint64_t tmpVal = 0;
1031 std::string tmpStr;
1032 uint32_t result = readJSONArrayStart();
1033 result += readJSONString(tmpStr);
1034 elemType = getTypeIDForTypeName(tmpStr);
1035 result += readJSONInteger(tmpVal);
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001036 if (tmpVal > (std::numeric_limits<uint32_t>::max)())
Roger Meierb69d24d2012-10-04 18:02:15 +00001037 throw TProtocolException(TProtocolException::SIZE_LIMIT);
1038 size = static_cast<uint32_t>(tmpVal);
zeshuai00786352b42020-06-15 17:00:33 +08001039
1040 TList list(elemType, size);
1041 checkReadBytesAvailable(list);
1042
David Reissdb0ea152008-02-18 01:49:37 +00001043 return result;
1044}
1045
1046uint32_t TJSONProtocol::readListEnd() {
1047 return readJSONArrayEnd();
1048}
1049
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001050uint32_t TJSONProtocol::readSetBegin(TType& elemType, uint32_t& size) {
David Reissdb0ea152008-02-18 01:49:37 +00001051 uint64_t tmpVal = 0;
1052 std::string tmpStr;
1053 uint32_t result = readJSONArrayStart();
1054 result += readJSONString(tmpStr);
1055 elemType = getTypeIDForTypeName(tmpStr);
1056 result += readJSONInteger(tmpVal);
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001057 if (tmpVal > (std::numeric_limits<uint32_t>::max)())
Roger Meierb69d24d2012-10-04 18:02:15 +00001058 throw TProtocolException(TProtocolException::SIZE_LIMIT);
1059 size = static_cast<uint32_t>(tmpVal);
zeshuai00786352b42020-06-15 17:00:33 +08001060
1061 TSet set(elemType, size);
1062 checkReadBytesAvailable(set);
1063
David Reissdb0ea152008-02-18 01:49:37 +00001064 return result;
1065}
1066
1067uint32_t TJSONProtocol::readSetEnd() {
1068 return readJSONArrayEnd();
1069}
1070
1071uint32_t TJSONProtocol::readBool(bool& value) {
1072 return readJSONInteger(value);
1073}
1074
Konrad Grochowski3b5dacb2014-11-24 10:55:31 +01001075// readByte() must be handled properly because boost::lexical cast sees int8_t
David Reissdb0ea152008-02-18 01:49:37 +00001076// as a text type instead of an integer type
1077uint32_t TJSONProtocol::readByte(int8_t& byte) {
Sebastian Zenker042580f2019-01-29 15:48:12 +01001078 auto tmp = (int16_t)byte;
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001079 uint32_t result = readJSONInteger(tmp);
David Reissdb0ea152008-02-18 01:49:37 +00001080 assert(tmp < 256);
1081 byte = (int8_t)tmp;
1082 return result;
1083}
1084
1085uint32_t TJSONProtocol::readI16(int16_t& i16) {
1086 return readJSONInteger(i16);
1087}
1088
1089uint32_t TJSONProtocol::readI32(int32_t& i32) {
1090 return readJSONInteger(i32);
1091}
1092
1093uint32_t TJSONProtocol::readI64(int64_t& i64) {
1094 return readJSONInteger(i64);
1095}
1096
1097uint32_t TJSONProtocol::readDouble(double& dub) {
1098 return readJSONDouble(dub);
1099}
1100
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001101uint32_t TJSONProtocol::readString(std::string& str) {
David Reissdb0ea152008-02-18 01:49:37 +00001102 return readJSONString(str);
1103}
1104
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001105uint32_t TJSONProtocol::readBinary(std::string& str) {
David Reissdb0ea152008-02-18 01:49:37 +00001106 return readJSONBase64(str);
1107}
zeshuai00786352b42020-06-15 17:00:33 +08001108
1109// Return the minimum number of bytes a type will consume on the wire
1110int TJSONProtocol::getMinSerializedSize(TType type)
1111{
1112 switch (type)
1113 {
1114 case T_STOP: return 0;
1115 case T_VOID: return 0;
1116 case T_BOOL: return 1; // written as int
1117 case T_BYTE: return 1;
1118 case T_DOUBLE: return 1;
1119 case T_I16: return 1;
1120 case T_I32: return 1;
1121 case T_I64: return 1;
1122 case T_STRING: return 2; // empty string
1123 case T_STRUCT: return 2; // empty struct
1124 case T_MAP: return 2; // empty map
1125 case T_SET: return 2; // empty set
1126 case T_LIST: return 2; // empty list
1127 default: throw TProtocolException(TProtocolException::UNKNOWN, "unrecognized type code");
1128 }
1129}
1130
Konrad Grochowski16a23a62014-11-13 15:33:38 +01001131}
1132}
1133} // apache::thrift::protocol