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