2017
[folly.git] / folly / json.cpp
1 /*
2  * Copyright 2017 Facebook, Inc.
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 <folly/json.h>
18 #include <cassert>
19 #include <boost/next_prior.hpp>
20 #include <boost/algorithm/string.hpp>
21
22 #include <folly/Conv.h>
23 #include <folly/Portability.h>
24 #include <folly/Range.h>
25 #include <folly/String.h>
26 #include <folly/Unicode.h>
27 #include <folly/portability/Constexpr.h>
28
29 namespace folly {
30
31 //////////////////////////////////////////////////////////////////////
32
33 namespace json {
34 namespace {
35
36 struct Printer {
37   explicit Printer(
38       std::string& out,
39       unsigned* indentLevel,
40       serialization_opts const* opts)
41       : out_(out), indentLevel_(indentLevel), opts_(*opts) {}
42
43   void operator()(dynamic const& v) const {
44     switch (v.type()) {
45     case dynamic::DOUBLE:
46       if (!opts_.allow_nan_inf &&
47           (std::isnan(v.asDouble()) || std::isinf(v.asDouble()))) {
48         throw std::runtime_error("folly::toJson: JSON object value was a "
49           "NaN or INF");
50       }
51       toAppend(v.asDouble(), &out_, opts_.double_mode, opts_.double_num_digits);
52       break;
53     case dynamic::INT64: {
54       auto intval = v.asInt();
55       if (opts_.javascript_safe) {
56         // Use folly::to to check that this integer can be represented
57         // as a double without loss of precision.
58         intval = int64_t(to<double>(intval));
59       }
60       toAppend(intval, &out_);
61       break;
62     }
63     case dynamic::BOOL:
64       out_ += v.asBool() ? "true" : "false";
65       break;
66     case dynamic::NULLT:
67       out_ += "null";
68       break;
69     case dynamic::STRING:
70       escapeString(v.asString(), out_, opts_);
71       break;
72     case dynamic::OBJECT:
73       printObject(v);
74       break;
75     case dynamic::ARRAY:
76       printArray(v);
77       break;
78     default:
79       CHECK(0) << "Bad type " << v.type();
80     }
81   }
82
83 private:
84   void printKV(const std::pair<const dynamic, dynamic>& p) const {
85     if (!opts_.allow_non_string_keys && !p.first.isString()) {
86       throw std::runtime_error("folly::toJson: JSON object key was not a "
87         "string");
88     }
89     (*this)(p.first);
90     mapColon();
91     (*this)(p.second);
92   }
93
94   template <typename Iterator>
95   void printKVPairs(Iterator begin, Iterator end) const {
96     printKV(*begin);
97     for (++begin; begin != end; ++begin) {
98       out_ += ',';
99       newline();
100       printKV(*begin);
101     }
102   }
103
104   void printObject(dynamic const& o) const {
105     if (o.empty()) {
106       out_ += "{}";
107       return;
108     }
109
110     out_ += '{';
111     indent();
112     newline();
113     if (opts_.sort_keys) {
114       std::vector<std::pair<dynamic, dynamic>> items(
115         o.items().begin(), o.items().end());
116       std::sort(items.begin(), items.end());
117       printKVPairs(items.begin(), items.end());
118     } else {
119       printKVPairs(o.items().begin(), o.items().end());
120     }
121     outdent();
122     newline();
123     out_ += '}';
124   }
125
126   void printArray(dynamic const& a) const {
127     if (a.empty()) {
128       out_ += "[]";
129       return;
130     }
131
132     out_ += '[';
133     indent();
134     newline();
135     (*this)(a[0]);
136     for (auto& val : range(boost::next(a.begin()), a.end())) {
137       out_ += ',';
138       newline();
139       (*this)(val);
140     }
141     outdent();
142     newline();
143     out_ += ']';
144   }
145
146 private:
147   void outdent() const {
148     if (indentLevel_) {
149       --*indentLevel_;
150     }
151   }
152
153   void indent() const {
154     if (indentLevel_) {
155       ++*indentLevel_;
156     }
157   }
158
159   void newline() const {
160     if (indentLevel_) {
161       out_ += to<std::string>('\n', std::string(*indentLevel_ * 2, ' '));
162     }
163   }
164
165   void mapColon() const {
166     out_ += indentLevel_ ? " : " : ":";
167   }
168
169 private:
170  std::string& out_;
171  unsigned* const indentLevel_;
172  serialization_opts const& opts_;
173 };
174
175   //////////////////////////////////////////////////////////////////////
176
177   struct ParseError : std::runtime_error {
178     explicit ParseError(int line)
179       : std::runtime_error(to<std::string>("json parse error on line ", line))
180     {}
181
182     explicit ParseError(int line, std::string const& context,
183         std::string const& expected)
184       : std::runtime_error(to<std::string>("json parse error on line ", line,
185           !context.empty() ? to<std::string>(" near `", context, '\'')
186                           : "",
187           ": ", expected))
188     {}
189
190     explicit ParseError(std::string const& msg)
191       : std::runtime_error("json parse error: " + msg)
192     {}
193   };
194
195 // Wraps our input buffer with some helper functions.
196 struct Input {
197   explicit Input(StringPiece range, json::serialization_opts const* opts)
198       : range_(range)
199       , opts_(*opts)
200       , lineNum_(0)
201   {
202     storeCurrent();
203   }
204
205   Input(Input const&) = delete;
206   Input& operator=(Input const&) = delete;
207
208   char const* begin() const { return range_.begin(); }
209
210   // Parse ahead for as long as the supplied predicate is satisfied,
211   // returning a range of what was skipped.
212   template<class Predicate>
213   StringPiece skipWhile(const Predicate& p) {
214     std::size_t skipped = 0;
215     for (; skipped < range_.size(); ++skipped) {
216       if (!p(range_[skipped])) {
217         break;
218       }
219       if (range_[skipped] == '\n') {
220         ++lineNum_;
221       }
222     }
223     auto ret = range_.subpiece(0, skipped);
224     range_.advance(skipped);
225     storeCurrent();
226     return ret;
227   }
228
229   StringPiece skipDigits() {
230     return skipWhile([] (char c) { return c >= '0' && c <= '9'; });
231   }
232
233   StringPiece skipMinusAndDigits() {
234     bool firstChar = true;
235     return skipWhile([&firstChar] (char c) {
236         bool result = (c >= '0' && c <= '9') || (firstChar && c == '-');
237         firstChar = false;
238         return result;
239       });
240   }
241
242   void skipWhitespace() {
243     range_ = folly::skipWhitespace(range_);
244     storeCurrent();
245   }
246
247   void expect(char c) {
248     if (**this != c) {
249       throw ParseError(lineNum_, context(),
250         to<std::string>("expected '", c, '\''));
251     }
252     ++*this;
253   }
254
255   std::size_t size() const {
256     return range_.size();
257   }
258
259   int operator*() const {
260     return current_;
261   }
262
263   void operator++() {
264     range_.pop_front();
265     storeCurrent();
266   }
267
268   template<class T>
269   T extract() {
270     try {
271       return to<T>(&range_);
272     } catch (std::exception const& e) {
273       error(e.what());
274     }
275   }
276
277   bool consume(StringPiece str) {
278     if (boost::starts_with(range_, str)) {
279       range_.advance(str.size());
280       storeCurrent();
281       return true;
282     }
283     return false;
284   }
285
286   std::string context() const {
287     return range_.subpiece(0, 16 /* arbitrary */).toString();
288   }
289
290   dynamic error(char const* what) const {
291     throw ParseError(lineNum_, context(), what);
292   }
293
294   json::serialization_opts const& getOpts() {
295     return opts_;
296   }
297
298   void incrementRecursionLevel() {
299     if (currentRecursionLevel_ > opts_.recursion_limit) {
300       error("recursion limit exceeded");
301     }
302     currentRecursionLevel_++;
303   }
304
305   void decrementRecursionLevel() {
306     currentRecursionLevel_--;
307   }
308
309  private:
310   void storeCurrent() {
311     current_ = range_.empty() ? EOF : range_.front();
312   }
313
314 private:
315   StringPiece range_;
316   json::serialization_opts const& opts_;
317   unsigned lineNum_;
318   int current_;
319   unsigned int currentRecursionLevel_{0};
320 };
321
322 class RecursionGuard {
323  public:
324   explicit RecursionGuard(Input& in) : in_(in) {
325     in_.incrementRecursionLevel();
326   }
327
328   ~RecursionGuard() {
329     in_.decrementRecursionLevel();
330   }
331
332  private:
333   Input& in_;
334 };
335
336 dynamic parseValue(Input& in);
337 std::string parseString(Input& in);
338 dynamic parseNumber(Input& in);
339
340 dynamic parseObject(Input& in) {
341   assert(*in == '{');
342   ++in;
343
344   dynamic ret = dynamic::object;
345
346   in.skipWhitespace();
347   if (*in == '}') {
348     ++in;
349     return ret;
350   }
351
352   for (;;) {
353     if (in.getOpts().allow_trailing_comma && *in == '}') {
354       break;
355     }
356     if (*in == '\"') { // string
357       auto key = parseString(in);
358       in.skipWhitespace();
359       in.expect(':');
360       in.skipWhitespace();
361       ret.insert(std::move(key), parseValue(in));
362     } else if (!in.getOpts().allow_non_string_keys) {
363       in.error("expected string for object key name");
364     } else {
365       auto key = parseValue(in);
366       in.skipWhitespace();
367       in.expect(':');
368       in.skipWhitespace();
369       ret.insert(std::move(key), parseValue(in));
370     }
371
372     in.skipWhitespace();
373     if (*in != ',') {
374       break;
375     }
376     ++in;
377     in.skipWhitespace();
378   }
379   in.expect('}');
380
381   return ret;
382 }
383
384 dynamic parseArray(Input& in) {
385   assert(*in == '[');
386   ++in;
387
388   dynamic ret = dynamic::array;
389
390   in.skipWhitespace();
391   if (*in == ']') {
392     ++in;
393     return ret;
394   }
395
396   for (;;) {
397     if (in.getOpts().allow_trailing_comma && *in == ']') {
398       break;
399     }
400     ret.push_back(parseValue(in));
401     in.skipWhitespace();
402     if (*in != ',') {
403       break;
404     }
405     ++in;
406     in.skipWhitespace();
407   }
408   in.expect(']');
409
410   return ret;
411 }
412
413 dynamic parseNumber(Input& in) {
414   bool const negative = (*in == '-');
415   if (negative && in.consume("-Infinity")) {
416     if (in.getOpts().parse_numbers_as_strings) {
417       return "-Infinity";
418     } else {
419       return -std::numeric_limits<double>::infinity();
420     }
421   }
422
423   auto integral = in.skipMinusAndDigits();
424   if (negative && integral.size() < 2) {
425     in.error("expected digits after `-'");
426   }
427
428   auto const wasE = *in == 'e' || *in == 'E';
429
430   constexpr const char* maxInt = "9223372036854775807";
431   constexpr const char* minInt = "-9223372036854775808";
432   constexpr auto maxIntLen = constexpr_strlen(maxInt);
433   constexpr auto minIntLen = constexpr_strlen(minInt);
434
435   if (*in != '.' && !wasE && in.getOpts().parse_numbers_as_strings) {
436     return integral;
437   }
438
439   if (*in != '.' && !wasE) {
440     if (LIKELY(!in.getOpts().double_fallback || integral.size() < maxIntLen) ||
441         (!negative && integral.size() == maxIntLen && integral <= maxInt) ||
442         (negative && integral.size() == minIntLen && integral <= minInt)) {
443       auto val = to<int64_t>(integral);
444       in.skipWhitespace();
445       return val;
446     } else {
447       auto val = to<double>(integral);
448       in.skipWhitespace();
449       return val;
450     }
451   }
452
453   auto end = !wasE ? (++in, in.skipDigits().end()) : in.begin();
454   if (*in == 'e' || *in == 'E') {
455     ++in;
456     if (*in == '+' || *in == '-') {
457       ++in;
458     }
459     auto expPart = in.skipDigits();
460     end = expPart.end();
461   }
462   auto fullNum = range(integral.begin(), end);
463   if (in.getOpts().parse_numbers_as_strings) {
464     return fullNum;
465   }
466   auto val = to<double>(fullNum);
467   return val;
468 }
469
470 std::string decodeUnicodeEscape(Input& in) {
471   auto hexVal = [&] (int c) -> uint16_t {
472     return uint16_t(
473            c >= '0' && c <= '9' ? c - '0' :
474            c >= 'a' && c <= 'f' ? c - 'a' + 10 :
475            c >= 'A' && c <= 'F' ? c - 'A' + 10 :
476            (in.error("invalid hex digit"), 0));
477   };
478
479   auto readHex = [&]() -> uint16_t {
480     if (in.size() < 4) {
481       in.error("expected 4 hex digits");
482     }
483
484     uint16_t ret = hexVal(*in) * 4096;
485     ++in;
486     ret += hexVal(*in) * 256;
487     ++in;
488     ret += hexVal(*in) * 16;
489     ++in;
490     ret += hexVal(*in);
491     ++in;
492     return ret;
493   };
494
495   /*
496    * If the value encoded is in the surrogate pair range, we need to
497    * make sure there is another escape that we can use also.
498    */
499   uint32_t codePoint = readHex();
500   if (codePoint >= 0xd800 && codePoint <= 0xdbff) {
501     if (!in.consume("\\u")) {
502       in.error("expected another unicode escape for second half of "
503         "surrogate pair");
504     }
505     uint16_t second = readHex();
506     if (second >= 0xdc00 && second <= 0xdfff) {
507       codePoint = 0x10000 + ((codePoint & 0x3ff) << 10) +
508                   (second & 0x3ff);
509     } else {
510       in.error("second character in surrogate pair is invalid");
511     }
512   } else if (codePoint >= 0xdc00 && codePoint <= 0xdfff) {
513     in.error("invalid unicode code point (in range [0xdc00,0xdfff])");
514   }
515
516   return codePointToUtf8(codePoint);
517 }
518
519 std::string parseString(Input& in) {
520   assert(*in == '\"');
521   ++in;
522
523   std::string ret;
524   for (;;) {
525     auto range = in.skipWhile(
526       [] (char c) { return c != '\"' && c != '\\'; }
527     );
528     ret.append(range.begin(), range.end());
529
530     if (*in == '\"') {
531       ++in;
532       break;
533     }
534     if (*in == '\\') {
535       ++in;
536       switch (*in) {
537       case '\"':    ret.push_back('\"'); ++in; break;
538       case '\\':    ret.push_back('\\'); ++in; break;
539       case '/':     ret.push_back('/');  ++in; break;
540       case 'b':     ret.push_back('\b'); ++in; break;
541       case 'f':     ret.push_back('\f'); ++in; break;
542       case 'n':     ret.push_back('\n'); ++in; break;
543       case 'r':     ret.push_back('\r'); ++in; break;
544       case 't':     ret.push_back('\t'); ++in; break;
545       case 'u':     ++in; ret += decodeUnicodeEscape(in); break;
546       default:
547         in.error(to<std::string>("unknown escape ", *in, " in string").c_str());
548       }
549       continue;
550     }
551     if (*in == EOF) {
552       in.error("unterminated string");
553     }
554     if (!*in) {
555       /*
556        * Apparently we're actually supposed to ban all control
557        * characters from strings.  This seems unnecessarily
558        * restrictive, so we're only banning zero bytes.  (Since the
559        * string is presumed to be UTF-8 encoded it's fine to just
560        * check this way.)
561        */
562       in.error("null byte in string");
563     }
564
565     ret.push_back(char(*in));
566     ++in;
567   }
568
569   return ret;
570 }
571
572 dynamic parseValue(Input& in) {
573   RecursionGuard guard(in);
574
575   in.skipWhitespace();
576   return *in == '[' ? parseArray(in) :
577          *in == '{' ? parseObject(in) :
578          *in == '\"' ? parseString(in) :
579          (*in == '-' || (*in >= '0' && *in <= '9')) ? parseNumber(in) :
580          in.consume("true") ? true :
581          in.consume("false") ? false :
582          in.consume("null") ? nullptr :
583          in.consume("Infinity") ?
584           (in.getOpts().parse_numbers_as_strings ? (dynamic)"Infinity" :
585             (dynamic)std::numeric_limits<double>::infinity()) :
586          in.consume("NaN") ?
587            (in.getOpts().parse_numbers_as_strings ? (dynamic)"NaN" :
588              (dynamic)std::numeric_limits<double>::quiet_NaN()) :
589          in.error("expected json value");
590 }
591
592 }
593
594 //////////////////////////////////////////////////////////////////////
595
596 std::string serialize(dynamic const& dyn, serialization_opts const& opts) {
597   std::string ret;
598   unsigned indentLevel = 0;
599   Printer p(ret, opts.pretty_formatting ? &indentLevel : nullptr, &opts);
600   p(dyn);
601   return ret;
602 }
603
604 // Escape a string so that it is legal to print it in JSON text.
605 void escapeString(
606     StringPiece input,
607     std::string& out,
608     const serialization_opts& opts) {
609   auto hexDigit = [] (uint8_t c) -> char {
610     return c < 10 ? c + '0' : c - 10 + 'a';
611   };
612
613   out.push_back('\"');
614
615   auto* p = reinterpret_cast<const unsigned char*>(input.begin());
616   auto* q = reinterpret_cast<const unsigned char*>(input.begin());
617   auto* e = reinterpret_cast<const unsigned char*>(input.end());
618
619   while (p < e) {
620     // Since non-ascii encoding inherently does utf8 validation
621     // we explicitly validate utf8 only if non-ascii encoding is disabled.
622     if ((opts.validate_utf8 || opts.skip_invalid_utf8)
623         && !opts.encode_non_ascii) {
624       // to achieve better spatial and temporal coherence
625       // we do utf8 validation progressively along with the
626       // string-escaping instead of two separate passes
627
628       // as the encoding progresses, q will stay at or ahead of p
629       CHECK(q >= p);
630
631       // as p catches up with q, move q forward
632       if (q == p) {
633         // calling utf8_decode has the side effect of
634         // checking that utf8 encodings are valid
635         char32_t v = utf8ToCodePoint(q, e, opts.skip_invalid_utf8);
636         if (opts.skip_invalid_utf8 && v == U'\ufffd') {
637           out.append(u8"\ufffd");
638           p = q;
639           continue;
640         }
641       }
642     }
643     if (opts.encode_non_ascii && (*p & 0x80)) {
644       // note that this if condition captures utf8 chars
645       // with value > 127, so size > 1 byte
646       char32_t v = utf8ToCodePoint(p, e, opts.skip_invalid_utf8);
647       out.append("\\u");
648       out.push_back(hexDigit(uint8_t(v >> 12)));
649       out.push_back(hexDigit((v >> 8) & 0x0f));
650       out.push_back(hexDigit((v >> 4) & 0x0f));
651       out.push_back(hexDigit(v & 0x0f));
652     } else if (*p == '\\' || *p == '\"') {
653       out.push_back('\\');
654       out.push_back(char(*p++));
655     } else if (*p <= 0x1f) {
656       switch (*p) {
657         case '\b': out.append("\\b"); p++; break;
658         case '\f': out.append("\\f"); p++; break;
659         case '\n': out.append("\\n"); p++; break;
660         case '\r': out.append("\\r"); p++; break;
661         case '\t': out.append("\\t"); p++; break;
662         default:
663           // note that this if condition captures non readable chars
664           // with value < 32, so size = 1 byte (e.g control chars).
665           out.append("\\u00");
666           out.push_back(hexDigit((*p & 0xf0) >> 4));
667           out.push_back(hexDigit(*p & 0xf));
668           p++;
669       }
670     } else {
671       out.push_back(*p++);
672     }
673   }
674
675   out.push_back('\"');
676 }
677
678 std::string stripComments(StringPiece jsonC) {
679   std::string result;
680   enum class State {
681     None,
682     InString,
683     InlineComment,
684     LineComment
685   } state = State::None;
686
687   for (size_t i = 0; i < jsonC.size(); ++i) {
688     auto s = jsonC.subpiece(i);
689     switch (state) {
690       case State::None:
691         if (s.startsWith("/*")) {
692           state = State::InlineComment;
693           ++i;
694           continue;
695         } else if (s.startsWith("//")) {
696           state = State::LineComment;
697           ++i;
698           continue;
699         } else if (s[0] == '\"') {
700           state = State::InString;
701         }
702         result.push_back(s[0]);
703         break;
704       case State::InString:
705         if (s[0] == '\\') {
706           if (UNLIKELY(s.size() == 1)) {
707             throw std::logic_error("Invalid JSONC: string is not terminated");
708           }
709           result.push_back(s[0]);
710           result.push_back(s[1]);
711           ++i;
712           continue;
713         } else if (s[0] == '\"') {
714           state = State::None;
715         }
716         result.push_back(s[0]);
717         break;
718       case State::InlineComment:
719         if (s.startsWith("*/")) {
720           state = State::None;
721           ++i;
722         }
723         break;
724       case State::LineComment:
725         if (s[0] == '\n') {
726           // skip the line break. It doesn't matter.
727           state = State::None;
728         }
729         break;
730       default:
731         throw std::logic_error("Unknown comment state");
732     }
733   }
734   return result;
735 }
736
737 }
738
739 //////////////////////////////////////////////////////////////////////
740
741 dynamic parseJson(StringPiece range) {
742   return parseJson(range, json::serialization_opts());
743 }
744
745 dynamic parseJson(
746     StringPiece range,
747     json::serialization_opts const& opts) {
748
749   json::Input in(range, &opts);
750
751   auto ret = parseValue(in);
752   in.skipWhitespace();
753   if (in.size() && *in != '\0') {
754     in.error("parsing didn't consume all input");
755   }
756   return ret;
757 }
758
759 std::string toJson(dynamic const& dyn) {
760   return json::serialize(dyn, json::serialization_opts());
761 }
762
763 std::string toPrettyJson(dynamic const& dyn) {
764   json::serialization_opts opts;
765   opts.pretty_formatting = true;
766   return json::serialize(dyn, opts);
767 }
768
769 //////////////////////////////////////////////////////////////////////
770 // dynamic::print_as_pseudo_json() is implemented here for header
771 // ordering reasons (most of the dynamic implementation is in
772 // dynamic-inl.h, which we don't want to include json.h).
773
774 void dynamic::print_as_pseudo_json(std::ostream& out) const {
775   json::serialization_opts opts;
776   opts.allow_non_string_keys = true;
777   opts.allow_nan_inf = true;
778   out << json::serialize(*this, opts);
779 }
780
781 void PrintTo(const dynamic& dyn, std::ostream* os) {
782   json::serialization_opts opts;
783   opts.allow_nan_inf = true;
784   opts.allow_non_string_keys = true;
785   opts.pretty_formatting = true;
786   opts.sort_keys = true;
787   *os << json::serialize(dyn, opts);
788 }
789
790 //////////////////////////////////////////////////////////////////////
791
792 }