JSONSchema.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  1. /*
  2. * Copyright 2015-present 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. #include <folly/experimental/JSONSchema.h>
  17. #include <boost/algorithm/string/replace.hpp>
  18. #include <boost/regex.hpp>
  19. #include <folly/CPortability.h>
  20. #include <folly/Conv.h>
  21. #include <folly/Memory.h>
  22. #include <folly/Optional.h>
  23. #include <folly/Singleton.h>
  24. #include <folly/String.h>
  25. #include <folly/json.h>
  26. namespace folly {
  27. namespace jsonschema {
  28. namespace {
  29. /**
  30. * We throw this exception when schema validation fails.
  31. */
  32. struct FOLLY_EXPORT SchemaError : std::runtime_error {
  33. SchemaError(SchemaError&&) = default;
  34. SchemaError(const SchemaError&) = default;
  35. SchemaError(folly::StringPiece expected, const dynamic& value)
  36. : std::runtime_error(to<std::string>(
  37. "Expected to get ",
  38. expected,
  39. " for value ",
  40. toJson(value))) {}
  41. SchemaError(
  42. folly::StringPiece expected,
  43. const dynamic& schema,
  44. const dynamic& value)
  45. : std::runtime_error(to<std::string>(
  46. "Expected to get ",
  47. expected,
  48. toJson(schema),
  49. " for value ",
  50. toJson(value))) {}
  51. };
  52. template <class... Args>
  53. Optional<SchemaError> makeError(Args&&... args) {
  54. return Optional<SchemaError>(SchemaError(std::forward<Args>(args)...));
  55. }
  56. struct ValidationContext;
  57. struct IValidator {
  58. virtual ~IValidator() = default;
  59. private:
  60. friend struct ValidationContext;
  61. virtual Optional<SchemaError> validate(
  62. ValidationContext&,
  63. const dynamic& value) const = 0;
  64. };
  65. /**
  66. * This is a 'context' used only when executing the validators to validate some
  67. * json. It keeps track of which validators have been executed on which json so
  68. * we can detect infinite recursion.
  69. */
  70. struct ValidationContext {
  71. Optional<SchemaError> validate(IValidator* validator, const dynamic& value) {
  72. auto ret = seen.insert(std::make_pair(validator, &value));
  73. if (!ret.second) {
  74. throw std::runtime_error("Infinite recursion detected");
  75. }
  76. return validator->validate(*this, value);
  77. }
  78. private:
  79. std::unordered_set<std::pair<const IValidator*, const dynamic*>> seen;
  80. };
  81. /**
  82. * This is a 'context' used only when building the schema validators from a
  83. * piece of json. It stores the original schema and the set of refs, so that we
  84. * can have parts of the schema refer to other parts.
  85. */
  86. struct SchemaValidatorContext final {
  87. explicit SchemaValidatorContext(const dynamic& s) : schema(s) {}
  88. const dynamic& schema;
  89. std::unordered_map<std::string, IValidator*> refs;
  90. };
  91. /**
  92. * Root validator for a schema.
  93. */
  94. struct SchemaValidator final : IValidator, public Validator {
  95. SchemaValidator() = default;
  96. void loadSchema(SchemaValidatorContext& context, const dynamic& schema);
  97. Optional<SchemaError> validate(ValidationContext&, const dynamic& value)
  98. const override;
  99. // Validator interface
  100. void validate(const dynamic& value) const override;
  101. exception_wrapper try_validate(const dynamic& value) const noexcept override;
  102. static std::unique_ptr<SchemaValidator> make(
  103. SchemaValidatorContext& context,
  104. const dynamic& schema) {
  105. // We break apart the constructor and actually loading the schema so that
  106. // we can handle the case where a schema refers to itself, e.g. via
  107. // "$ref": "#".
  108. auto v = std::make_unique<SchemaValidator>();
  109. v->loadSchema(context, schema);
  110. return v;
  111. }
  112. private:
  113. std::vector<std::unique_ptr<IValidator>> validators_;
  114. };
  115. struct MultipleOfValidator final : IValidator {
  116. explicit MultipleOfValidator(dynamic schema) : schema_(std::move(schema)) {}
  117. Optional<SchemaError> validate(ValidationContext&, const dynamic& value)
  118. const override {
  119. if (!schema_.isNumber() || !value.isNumber()) {
  120. return none;
  121. }
  122. if (schema_.isDouble() || value.isDouble()) {
  123. const auto rem = std::remainder(value.asDouble(), schema_.asDouble());
  124. if (std::abs(rem) > std::numeric_limits<double>::epsilon()) {
  125. return makeError("a multiple of ", schema_, value);
  126. }
  127. } else { // both ints
  128. if ((value.getInt() % schema_.getInt()) != 0) {
  129. return makeError("a multiple of ", schema_, value);
  130. }
  131. }
  132. return none;
  133. }
  134. dynamic schema_;
  135. };
  136. struct ComparisonValidator final : IValidator {
  137. enum class Type { MIN, MAX };
  138. ComparisonValidator(dynamic schema, const dynamic* exclusive, Type type)
  139. : schema_(std::move(schema)), exclusive_(false), type_(type) {
  140. if (exclusive && exclusive->isBool()) {
  141. exclusive_ = exclusive->getBool();
  142. }
  143. }
  144. template <typename Numeric>
  145. Optional<SchemaError>
  146. validateHelper(const dynamic& value, Numeric s, Numeric v) const {
  147. if (type_ == Type::MIN) {
  148. if (exclusive_) {
  149. if (v <= s) {
  150. return makeError("greater than ", schema_, value);
  151. }
  152. } else {
  153. if (v < s) {
  154. return makeError("greater than or equal to ", schema_, value);
  155. }
  156. }
  157. } else if (type_ == Type::MAX) {
  158. if (exclusive_) {
  159. if (v >= s) {
  160. return makeError("less than ", schema_, value);
  161. }
  162. } else {
  163. if (v > s) {
  164. return makeError("less than or equal to ", schema_, value);
  165. }
  166. }
  167. }
  168. return none;
  169. }
  170. Optional<SchemaError> validate(ValidationContext&, const dynamic& value)
  171. const override {
  172. if (!schema_.isNumber() || !value.isNumber()) {
  173. return none;
  174. }
  175. if (schema_.isDouble() || value.isDouble()) {
  176. return validateHelper(value, schema_.asDouble(), value.asDouble());
  177. } else { // both ints
  178. return validateHelper(value, schema_.asInt(), value.asInt());
  179. }
  180. }
  181. dynamic schema_;
  182. bool exclusive_;
  183. Type type_;
  184. };
  185. template <class Comparison>
  186. struct SizeValidator final : IValidator {
  187. explicit SizeValidator(const dynamic& schema, dynamic::Type type)
  188. : length_(-1), type_(type) {
  189. if (schema.isInt()) {
  190. length_ = schema.getInt();
  191. }
  192. }
  193. Optional<SchemaError> validate(ValidationContext&, const dynamic& value)
  194. const override {
  195. if (length_ < 0) {
  196. return none;
  197. }
  198. if (value.type() != type_) {
  199. return none;
  200. }
  201. if (!Comparison()(length_, int64_t(value.size()))) {
  202. return makeError("different length string/array/object", value);
  203. }
  204. return none;
  205. }
  206. int64_t length_;
  207. dynamic::Type type_;
  208. };
  209. struct StringPatternValidator final : IValidator {
  210. explicit StringPatternValidator(const dynamic& schema) {
  211. if (schema.isString()) {
  212. regex_ = boost::regex(schema.getString());
  213. }
  214. }
  215. Optional<SchemaError> validate(ValidationContext&, const dynamic& value)
  216. const override {
  217. if (!value.isString() || regex_.empty()) {
  218. return none;
  219. }
  220. if (!boost::regex_search(value.getString(), regex_)) {
  221. return makeError("string matching regex", value);
  222. }
  223. return none;
  224. }
  225. boost::regex regex_;
  226. };
  227. struct ArrayUniqueValidator final : IValidator {
  228. explicit ArrayUniqueValidator(const dynamic& schema) : unique_(false) {
  229. if (schema.isBool()) {
  230. unique_ = schema.getBool();
  231. }
  232. }
  233. Optional<SchemaError> validate(ValidationContext&, const dynamic& value)
  234. const override {
  235. if (!unique_ || !value.isArray()) {
  236. return none;
  237. }
  238. for (const auto& i : value) {
  239. for (const auto& j : value) {
  240. if (&i != &j && i == j) {
  241. return makeError("unique items in array", value);
  242. }
  243. }
  244. }
  245. return none;
  246. }
  247. bool unique_;
  248. };
  249. struct ArrayItemsValidator final : IValidator {
  250. ArrayItemsValidator(
  251. SchemaValidatorContext& context,
  252. const dynamic* items,
  253. const dynamic* additionalItems)
  254. : allowAdditionalItems_(true) {
  255. if (items && items->isObject()) {
  256. itemsValidator_ = SchemaValidator::make(context, *items);
  257. return; // Additional items is ignored
  258. } else if (items && items->isArray()) {
  259. for (const auto& item : *items) {
  260. itemsValidators_.emplace_back(SchemaValidator::make(context, item));
  261. }
  262. } else {
  263. // If items isn't present or is invalid, it defaults to an empty schema.
  264. itemsValidator_ = SchemaValidator::make(context, dynamic::object);
  265. }
  266. if (additionalItems) {
  267. if (additionalItems->isBool()) {
  268. allowAdditionalItems_ = additionalItems->getBool();
  269. } else if (additionalItems->isObject()) {
  270. additionalItemsValidator_ =
  271. SchemaValidator::make(context, *additionalItems);
  272. }
  273. }
  274. }
  275. Optional<SchemaError> validate(ValidationContext& vc, const dynamic& value)
  276. const override {
  277. if (!value.isArray()) {
  278. return none;
  279. }
  280. if (itemsValidator_) {
  281. for (const auto& v : value) {
  282. if (auto se = vc.validate(itemsValidator_.get(), v)) {
  283. return se;
  284. }
  285. }
  286. return none;
  287. }
  288. size_t pos = 0;
  289. for (; pos < value.size() && pos < itemsValidators_.size(); ++pos) {
  290. if (auto se = vc.validate(itemsValidators_[pos].get(), value[pos])) {
  291. return se;
  292. }
  293. }
  294. if (!allowAdditionalItems_ && pos < value.size()) {
  295. return makeError("no more additional items", value);
  296. }
  297. if (additionalItemsValidator_) {
  298. for (; pos < value.size(); ++pos) {
  299. if (auto se =
  300. vc.validate(additionalItemsValidator_.get(), value[pos])) {
  301. return se;
  302. }
  303. }
  304. }
  305. return none;
  306. }
  307. std::unique_ptr<IValidator> itemsValidator_;
  308. std::vector<std::unique_ptr<IValidator>> itemsValidators_;
  309. std::unique_ptr<IValidator> additionalItemsValidator_;
  310. bool allowAdditionalItems_;
  311. };
  312. struct RequiredValidator final : IValidator {
  313. explicit RequiredValidator(const dynamic& schema) {
  314. if (schema.isArray()) {
  315. for (const auto& item : schema) {
  316. if (item.isString()) {
  317. properties_.emplace_back(item.getString());
  318. }
  319. }
  320. }
  321. }
  322. Optional<SchemaError> validate(ValidationContext&, const dynamic& value)
  323. const override {
  324. if (value.isObject()) {
  325. for (const auto& prop : properties_) {
  326. if (!value.get_ptr(prop)) {
  327. return makeError("property ", prop, value);
  328. }
  329. }
  330. }
  331. return none;
  332. }
  333. private:
  334. std::vector<std::string> properties_;
  335. };
  336. struct PropertiesValidator final : IValidator {
  337. PropertiesValidator(
  338. SchemaValidatorContext& context,
  339. const dynamic* properties,
  340. const dynamic* patternProperties,
  341. const dynamic* additionalProperties)
  342. : allowAdditionalProperties_(true) {
  343. if (properties && properties->isObject()) {
  344. for (const auto& pair : properties->items()) {
  345. if (pair.first.isString()) {
  346. propertyValidators_[pair.first.getString()] =
  347. SchemaValidator::make(context, pair.second);
  348. }
  349. }
  350. }
  351. if (patternProperties && patternProperties->isObject()) {
  352. for (const auto& pair : patternProperties->items()) {
  353. if (pair.first.isString()) {
  354. patternPropertyValidators_.emplace_back(
  355. boost::regex(pair.first.getString()),
  356. SchemaValidator::make(context, pair.second));
  357. }
  358. }
  359. }
  360. if (additionalProperties) {
  361. if (additionalProperties->isBool()) {
  362. allowAdditionalProperties_ = additionalProperties->getBool();
  363. } else if (additionalProperties->isObject()) {
  364. additionalPropertyValidator_ =
  365. SchemaValidator::make(context, *additionalProperties);
  366. }
  367. }
  368. }
  369. Optional<SchemaError> validate(ValidationContext& vc, const dynamic& value)
  370. const override {
  371. if (!value.isObject()) {
  372. return none;
  373. }
  374. for (const auto& pair : value.items()) {
  375. if (!pair.first.isString()) {
  376. continue;
  377. }
  378. const std::string& key = pair.first.getString();
  379. auto it = propertyValidators_.find(key);
  380. bool matched = false;
  381. if (it != propertyValidators_.end()) {
  382. if (auto se = vc.validate(it->second.get(), pair.second)) {
  383. return se;
  384. }
  385. matched = true;
  386. }
  387. const std::string& strkey = key;
  388. for (const auto& ppv : patternPropertyValidators_) {
  389. if (boost::regex_search(strkey, ppv.first)) {
  390. if (auto se = vc.validate(ppv.second.get(), pair.second)) {
  391. return se;
  392. }
  393. matched = true;
  394. }
  395. }
  396. if (matched) {
  397. continue;
  398. }
  399. if (!allowAdditionalProperties_) {
  400. return makeError("no more additional properties", value);
  401. }
  402. if (additionalPropertyValidator_) {
  403. if (auto se =
  404. vc.validate(additionalPropertyValidator_.get(), pair.second)) {
  405. return se;
  406. }
  407. }
  408. }
  409. return none;
  410. }
  411. std::unordered_map<std::string, std::unique_ptr<IValidator>>
  412. propertyValidators_;
  413. std::vector<std::pair<boost::regex, std::unique_ptr<IValidator>>>
  414. patternPropertyValidators_;
  415. std::unique_ptr<IValidator> additionalPropertyValidator_;
  416. bool allowAdditionalProperties_;
  417. };
  418. struct DependencyValidator final : IValidator {
  419. DependencyValidator(SchemaValidatorContext& context, const dynamic& schema) {
  420. if (!schema.isObject()) {
  421. return;
  422. }
  423. for (const auto& pair : schema.items()) {
  424. if (!pair.first.isString()) {
  425. continue;
  426. }
  427. if (pair.second.isArray()) {
  428. auto p = make_pair(pair.first.getString(), std::vector<std::string>());
  429. for (const auto& item : pair.second) {
  430. if (item.isString()) {
  431. p.second.push_back(item.getString());
  432. }
  433. }
  434. propertyDep_.emplace_back(std::move(p));
  435. }
  436. if (pair.second.isObject()) {
  437. schemaDep_.emplace_back(
  438. pair.first.getString(),
  439. SchemaValidator::make(context, pair.second));
  440. }
  441. }
  442. }
  443. Optional<SchemaError> validate(ValidationContext& vc, const dynamic& value)
  444. const override {
  445. if (!value.isObject()) {
  446. return none;
  447. }
  448. for (const auto& pair : propertyDep_) {
  449. if (value.count(pair.first)) {
  450. for (const auto& prop : pair.second) {
  451. if (!value.count(prop)) {
  452. return makeError("property ", prop, value);
  453. }
  454. }
  455. }
  456. }
  457. for (const auto& pair : schemaDep_) {
  458. if (value.count(pair.first)) {
  459. if (auto se = vc.validate(pair.second.get(), value)) {
  460. return se;
  461. }
  462. }
  463. }
  464. return none;
  465. }
  466. std::vector<std::pair<std::string, std::vector<std::string>>> propertyDep_;
  467. std::vector<std::pair<std::string, std::unique_ptr<IValidator>>> schemaDep_;
  468. };
  469. struct EnumValidator final : IValidator {
  470. explicit EnumValidator(dynamic schema) : schema_(std::move(schema)) {}
  471. Optional<SchemaError> validate(ValidationContext&, const dynamic& value)
  472. const override {
  473. if (!schema_.isArray()) {
  474. return none;
  475. }
  476. for (const auto& item : schema_) {
  477. if (value == item) {
  478. return none;
  479. }
  480. }
  481. return makeError("one of enum values: ", schema_, value);
  482. }
  483. dynamic schema_;
  484. };
  485. struct TypeValidator final : IValidator {
  486. explicit TypeValidator(const dynamic& schema) {
  487. if (schema.isString()) {
  488. addType(schema.stringPiece());
  489. } else if (schema.isArray()) {
  490. for (const auto& item : schema) {
  491. if (item.isString()) {
  492. addType(item.stringPiece());
  493. }
  494. }
  495. }
  496. }
  497. Optional<SchemaError> validate(ValidationContext&, const dynamic& value)
  498. const override {
  499. auto it =
  500. std::find(allowedTypes_.begin(), allowedTypes_.end(), value.type());
  501. if (it == allowedTypes_.end()) {
  502. return makeError("a value of type ", typeStr_, value);
  503. }
  504. return none;
  505. }
  506. private:
  507. std::vector<dynamic::Type> allowedTypes_;
  508. std::string typeStr_; // for errors
  509. void addType(StringPiece value) {
  510. if (value == "array") {
  511. allowedTypes_.push_back(dynamic::Type::ARRAY);
  512. } else if (value == "boolean") {
  513. allowedTypes_.push_back(dynamic::Type::BOOL);
  514. } else if (value == "integer") {
  515. allowedTypes_.push_back(dynamic::Type::INT64);
  516. } else if (value == "number") {
  517. allowedTypes_.push_back(dynamic::Type::INT64);
  518. allowedTypes_.push_back(dynamic::Type::DOUBLE);
  519. } else if (value == "null") {
  520. allowedTypes_.push_back(dynamic::Type::NULLT);
  521. } else if (value == "object") {
  522. allowedTypes_.push_back(dynamic::Type::OBJECT);
  523. } else if (value == "string") {
  524. allowedTypes_.push_back(dynamic::Type::STRING);
  525. } else {
  526. return;
  527. }
  528. if (!typeStr_.empty()) {
  529. typeStr_ += ", ";
  530. }
  531. typeStr_ += value.str();
  532. }
  533. };
  534. struct AllOfValidator final : IValidator {
  535. AllOfValidator(SchemaValidatorContext& context, const dynamic& schema) {
  536. if (schema.isArray()) {
  537. for (const auto& item : schema) {
  538. validators_.emplace_back(SchemaValidator::make(context, item));
  539. }
  540. }
  541. }
  542. Optional<SchemaError> validate(ValidationContext& vc, const dynamic& value)
  543. const override {
  544. for (const auto& val : validators_) {
  545. if (auto se = vc.validate(val.get(), value)) {
  546. return se;
  547. }
  548. }
  549. return none;
  550. }
  551. std::vector<std::unique_ptr<IValidator>> validators_;
  552. };
  553. struct AnyOfValidator final : IValidator {
  554. enum class Type { EXACTLY_ONE, ONE_OR_MORE };
  555. AnyOfValidator(
  556. SchemaValidatorContext& context,
  557. const dynamic& schema,
  558. Type type)
  559. : type_(type) {
  560. if (schema.isArray()) {
  561. for (const auto& item : schema) {
  562. validators_.emplace_back(SchemaValidator::make(context, item));
  563. }
  564. }
  565. }
  566. Optional<SchemaError> validate(ValidationContext& vc, const dynamic& value)
  567. const override {
  568. std::vector<SchemaError> errors;
  569. for (const auto& val : validators_) {
  570. if (auto se = vc.validate(val.get(), value)) {
  571. errors.emplace_back(*se);
  572. }
  573. }
  574. const auto success = validators_.size() - errors.size();
  575. if (success == 0) {
  576. return makeError("at least one valid schema", value);
  577. } else if (success > 1 && type_ == Type::EXACTLY_ONE) {
  578. return makeError("exactly one valid schema", value);
  579. }
  580. return none;
  581. }
  582. Type type_;
  583. std::vector<std::unique_ptr<IValidator>> validators_;
  584. };
  585. struct RefValidator final : IValidator {
  586. explicit RefValidator(IValidator* validator) : validator_(validator) {}
  587. Optional<SchemaError> validate(ValidationContext& vc, const dynamic& value)
  588. const override {
  589. return vc.validate(validator_, value);
  590. }
  591. IValidator* validator_;
  592. };
  593. struct NotValidator final : IValidator {
  594. NotValidator(SchemaValidatorContext& context, const dynamic& schema)
  595. : validator_(SchemaValidator::make(context, schema)) {}
  596. Optional<SchemaError> validate(ValidationContext& vc, const dynamic& value)
  597. const override {
  598. if (vc.validate(validator_.get(), value)) {
  599. return none;
  600. }
  601. return makeError("Expected schema validation to fail", value);
  602. }
  603. std::unique_ptr<IValidator> validator_;
  604. };
  605. void SchemaValidator::loadSchema(
  606. SchemaValidatorContext& context,
  607. const dynamic& schema) {
  608. if (!schema.isObject() || schema.empty()) {
  609. return;
  610. }
  611. // Check for $ref, if we have one we won't apply anything else. Refs are
  612. // pointers to other parts of the json, e.g. #/foo/bar points to the schema
  613. // located at root["foo"]["bar"].
  614. if (const auto* p = schema.get_ptr("$ref")) {
  615. // We only support absolute refs, i.e. those starting with '#'
  616. if (p->isString() && p->stringPiece()[0] == '#') {
  617. auto it = context.refs.find(p->getString());
  618. if (it != context.refs.end()) {
  619. validators_.emplace_back(std::make_unique<RefValidator>(it->second));
  620. return;
  621. }
  622. // This is a ref, but we haven't loaded it yet. Find where it is based on
  623. // the root schema.
  624. std::vector<std::string> parts;
  625. split("/", p->stringPiece(), parts);
  626. const auto* s = &context.schema; // First part is '#'
  627. for (size_t i = 1; s && i < parts.size(); ++i) {
  628. // Per the standard, we must replace ~1 with / and then ~0 with ~
  629. boost::replace_all(parts[i], "~1", "/");
  630. boost::replace_all(parts[i], "~0", "~");
  631. if (s->isObject()) {
  632. s = s->get_ptr(parts[i]);
  633. continue;
  634. }
  635. if (s->isArray()) {
  636. try {
  637. const size_t pos = to<size_t>(parts[i]);
  638. if (pos < s->size()) {
  639. s = s->get_ptr(pos);
  640. continue;
  641. }
  642. } catch (const std::range_error&) {
  643. // ignore
  644. }
  645. }
  646. break;
  647. }
  648. // If you have a self-recursive reference, this avoids getting into an
  649. // infinite recursion, where we try to load a schema that just references
  650. // itself, and then we try to load it again, and so on.
  651. // Instead we load a pointer to the schema into the refs, so that any
  652. // future references to it will just see that pointer and won't try to
  653. // keep parsing further.
  654. if (s) {
  655. auto v = std::make_unique<SchemaValidator>();
  656. context.refs[p->getString()] = v.get();
  657. v->loadSchema(context, *s);
  658. validators_.emplace_back(std::move(v));
  659. return;
  660. }
  661. }
  662. }
  663. // Numeric validators
  664. if (const auto* p = schema.get_ptr("multipleOf")) {
  665. validators_.emplace_back(std::make_unique<MultipleOfValidator>(*p));
  666. }
  667. if (const auto* p = schema.get_ptr("maximum")) {
  668. validators_.emplace_back(std::make_unique<ComparisonValidator>(
  669. *p,
  670. schema.get_ptr("exclusiveMaximum"),
  671. ComparisonValidator::Type::MAX));
  672. }
  673. if (const auto* p = schema.get_ptr("minimum")) {
  674. validators_.emplace_back(std::make_unique<ComparisonValidator>(
  675. *p,
  676. schema.get_ptr("exclusiveMinimum"),
  677. ComparisonValidator::Type::MIN));
  678. }
  679. // String validators
  680. if (const auto* p = schema.get_ptr("maxLength")) {
  681. validators_.emplace_back(
  682. std::make_unique<SizeValidator<std::greater_equal<int64_t>>>(
  683. *p, dynamic::Type::STRING));
  684. }
  685. if (const auto* p = schema.get_ptr("minLength")) {
  686. validators_.emplace_back(
  687. std::make_unique<SizeValidator<std::less_equal<int64_t>>>(
  688. *p, dynamic::Type::STRING));
  689. }
  690. if (const auto* p = schema.get_ptr("pattern")) {
  691. validators_.emplace_back(std::make_unique<StringPatternValidator>(*p));
  692. }
  693. // Array validators
  694. const auto* items = schema.get_ptr("items");
  695. const auto* additionalItems = schema.get_ptr("additionalItems");
  696. if (items || additionalItems) {
  697. validators_.emplace_back(
  698. std::make_unique<ArrayItemsValidator>(context, items, additionalItems));
  699. }
  700. if (const auto* p = schema.get_ptr("maxItems")) {
  701. validators_.emplace_back(
  702. std::make_unique<SizeValidator<std::greater_equal<int64_t>>>(
  703. *p, dynamic::Type::ARRAY));
  704. }
  705. if (const auto* p = schema.get_ptr("minItems")) {
  706. validators_.emplace_back(
  707. std::make_unique<SizeValidator<std::less_equal<int64_t>>>(
  708. *p, dynamic::Type::ARRAY));
  709. }
  710. if (const auto* p = schema.get_ptr("uniqueItems")) {
  711. validators_.emplace_back(std::make_unique<ArrayUniqueValidator>(*p));
  712. }
  713. // Object validators
  714. const auto* properties = schema.get_ptr("properties");
  715. const auto* patternProperties = schema.get_ptr("patternProperties");
  716. const auto* additionalProperties = schema.get_ptr("additionalProperties");
  717. if (properties || patternProperties || additionalProperties) {
  718. validators_.emplace_back(std::make_unique<PropertiesValidator>(
  719. context, properties, patternProperties, additionalProperties));
  720. }
  721. if (const auto* p = schema.get_ptr("maxProperties")) {
  722. validators_.emplace_back(
  723. std::make_unique<SizeValidator<std::greater_equal<int64_t>>>(
  724. *p, dynamic::Type::OBJECT));
  725. }
  726. if (const auto* p = schema.get_ptr("minProperties")) {
  727. validators_.emplace_back(
  728. std::make_unique<SizeValidator<std::less_equal<int64_t>>>(
  729. *p, dynamic::Type::OBJECT));
  730. }
  731. if (const auto* p = schema.get_ptr("required")) {
  732. validators_.emplace_back(std::make_unique<RequiredValidator>(*p));
  733. }
  734. // Misc validators
  735. if (const auto* p = schema.get_ptr("dependencies")) {
  736. validators_.emplace_back(
  737. std::make_unique<DependencyValidator>(context, *p));
  738. }
  739. if (const auto* p = schema.get_ptr("enum")) {
  740. validators_.emplace_back(std::make_unique<EnumValidator>(*p));
  741. }
  742. if (const auto* p = schema.get_ptr("type")) {
  743. validators_.emplace_back(std::make_unique<TypeValidator>(*p));
  744. }
  745. if (const auto* p = schema.get_ptr("allOf")) {
  746. validators_.emplace_back(std::make_unique<AllOfValidator>(context, *p));
  747. }
  748. if (const auto* p = schema.get_ptr("anyOf")) {
  749. validators_.emplace_back(std::make_unique<AnyOfValidator>(
  750. context, *p, AnyOfValidator::Type::ONE_OR_MORE));
  751. }
  752. if (const auto* p = schema.get_ptr("oneOf")) {
  753. validators_.emplace_back(std::make_unique<AnyOfValidator>(
  754. context, *p, AnyOfValidator::Type::EXACTLY_ONE));
  755. }
  756. if (const auto* p = schema.get_ptr("not")) {
  757. validators_.emplace_back(std::make_unique<NotValidator>(context, *p));
  758. }
  759. }
  760. void SchemaValidator::validate(const dynamic& value) const {
  761. ValidationContext vc;
  762. if (auto se = validate(vc, value)) {
  763. throw *se;
  764. }
  765. }
  766. exception_wrapper SchemaValidator::try_validate(const dynamic& value) const
  767. noexcept {
  768. try {
  769. ValidationContext vc;
  770. if (auto se = validate(vc, value)) {
  771. return make_exception_wrapper<SchemaError>(*se);
  772. }
  773. } catch (const std::exception& e) {
  774. return exception_wrapper(std::current_exception(), e);
  775. } catch (...) {
  776. return exception_wrapper(std::current_exception());
  777. }
  778. return exception_wrapper();
  779. }
  780. Optional<SchemaError> SchemaValidator::validate(
  781. ValidationContext& vc,
  782. const dynamic& value) const {
  783. for (const auto& validator : validators_) {
  784. if (auto se = vc.validate(validator.get(), value)) {
  785. return se;
  786. }
  787. }
  788. return none;
  789. }
  790. /**
  791. * Metaschema, i.e. schema for schema.
  792. * Inlined from the $schema url
  793. */
  794. const char* metaschemaJson =
  795. "\
  796. { \
  797. \"id\": \"http://json-schema.org/draft-04/schema#\", \
  798. \"$schema\": \"http://json-schema.org/draft-04/schema#\", \
  799. \"description\": \"Core schema meta-schema\", \
  800. \"definitions\": { \
  801. \"schemaArray\": { \
  802. \"type\": \"array\", \
  803. \"minItems\": 1, \
  804. \"items\": { \"$ref\": \"#\" } \
  805. }, \
  806. \"positiveInteger\": { \
  807. \"type\": \"integer\", \
  808. \"minimum\": 0 \
  809. }, \
  810. \"positiveIntegerDefault0\": { \
  811. \"allOf\": [ \
  812. { \"$ref\": \"#/definitions/positiveInteger\" }, { \"default\": 0 } ]\
  813. }, \
  814. \"simpleTypes\": { \
  815. \"enum\": [ \"array\", \"boolean\", \"integer\", \
  816. \"null\", \"number\", \"object\", \"string\" ] \
  817. }, \
  818. \"stringArray\": { \
  819. \"type\": \"array\", \
  820. \"items\": { \"type\": \"string\" }, \
  821. \"minItems\": 1, \
  822. \"uniqueItems\": true \
  823. } \
  824. }, \
  825. \"type\": \"object\", \
  826. \"properties\": { \
  827. \"id\": { \
  828. \"type\": \"string\", \
  829. \"format\": \"uri\" \
  830. }, \
  831. \"$schema\": { \
  832. \"type\": \"string\", \
  833. \"format\": \"uri\" \
  834. }, \
  835. \"title\": { \
  836. \"type\": \"string\" \
  837. }, \
  838. \"description\": { \
  839. \"type\": \"string\" \
  840. }, \
  841. \"default\": {}, \
  842. \"multipleOf\": { \
  843. \"type\": \"number\", \
  844. \"minimum\": 0, \
  845. \"exclusiveMinimum\": true \
  846. }, \
  847. \"maximum\": { \
  848. \"type\": \"number\" \
  849. }, \
  850. \"exclusiveMaximum\": { \
  851. \"type\": \"boolean\", \
  852. \"default\": false \
  853. }, \
  854. \"minimum\": { \
  855. \"type\": \"number\" \
  856. }, \
  857. \"exclusiveMinimum\": { \
  858. \"type\": \"boolean\", \
  859. \"default\": false \
  860. }, \
  861. \"maxLength\": { \"$ref\": \"#/definitions/positiveInteger\" }, \
  862. \"minLength\": { \"$ref\": \"#/definitions/positiveIntegerDefault0\" },\
  863. \"pattern\": { \
  864. \"type\": \"string\", \
  865. \"format\": \"regex\" \
  866. }, \
  867. \"additionalItems\": { \
  868. \"anyOf\": [ \
  869. { \"type\": \"boolean\" }, \
  870. { \"$ref\": \"#\" } \
  871. ], \
  872. \"default\": {} \
  873. }, \
  874. \"items\": { \
  875. \"anyOf\": [ \
  876. { \"$ref\": \"#\" }, \
  877. { \"$ref\": \"#/definitions/schemaArray\" } \
  878. ], \
  879. \"default\": {} \
  880. }, \
  881. \"maxItems\": { \"$ref\": \"#/definitions/positiveInteger\" }, \
  882. \"minItems\": { \"$ref\": \"#/definitions/positiveIntegerDefault0\" }, \
  883. \"uniqueItems\": { \
  884. \"type\": \"boolean\", \
  885. \"default\": false \
  886. }, \
  887. \"maxProperties\": { \"$ref\": \"#/definitions/positiveInteger\" }, \
  888. \"minProperties\": { \
  889. \"$ref\": \"#/definitions/positiveIntegerDefault0\" }, \
  890. \"required\": { \"$ref\": \"#/definitions/stringArray\" }, \
  891. \"additionalProperties\": { \
  892. \"anyOf\": [ \
  893. { \"type\": \"boolean\" }, \
  894. { \"$ref\": \"#\" } \
  895. ], \
  896. \"default\": {} \
  897. }, \
  898. \"definitions\": { \
  899. \"type\": \"object\", \
  900. \"additionalProperties\": { \"$ref\": \"#\" }, \
  901. \"default\": {} \
  902. }, \
  903. \"properties\": { \
  904. \"type\": \"object\", \
  905. \"additionalProperties\": { \"$ref\": \"#\" }, \
  906. \"default\": {} \
  907. }, \
  908. \"patternProperties\": { \
  909. \"type\": \"object\", \
  910. \"additionalProperties\": { \"$ref\": \"#\" }, \
  911. \"default\": {} \
  912. }, \
  913. \"dependencies\": { \
  914. \"type\": \"object\", \
  915. \"additionalProperties\": { \
  916. \"anyOf\": [ \
  917. { \"$ref\": \"#\" }, \
  918. { \"$ref\": \"#/definitions/stringArray\" } \
  919. ] \
  920. } \
  921. }, \
  922. \"enum\": { \
  923. \"type\": \"array\", \
  924. \"minItems\": 1, \
  925. \"uniqueItems\": true \
  926. }, \
  927. \"type\": { \
  928. \"anyOf\": [ \
  929. { \"$ref\": \"#/definitions/simpleTypes\" }, \
  930. { \
  931. \"type\": \"array\", \
  932. \"items\": { \"$ref\": \"#/definitions/simpleTypes\" }, \
  933. \"minItems\": 1, \
  934. \"uniqueItems\": true \
  935. } \
  936. ] \
  937. }, \
  938. \"allOf\": { \"$ref\": \"#/definitions/schemaArray\" }, \
  939. \"anyOf\": { \"$ref\": \"#/definitions/schemaArray\" }, \
  940. \"oneOf\": { \"$ref\": \"#/definitions/schemaArray\" }, \
  941. \"not\": { \"$ref\": \"#\" } \
  942. }, \
  943. \"dependencies\": { \
  944. \"exclusiveMaximum\": [ \"maximum\" ], \
  945. \"exclusiveMinimum\": [ \"minimum\" ] \
  946. }, \
  947. \"default\": {} \
  948. }";
  949. folly::Singleton<Validator> schemaValidator([]() {
  950. return makeValidator(parseJson(metaschemaJson)).release();
  951. });
  952. } // namespace
  953. Validator::~Validator() = default;
  954. std::unique_ptr<Validator> makeValidator(const dynamic& schema) {
  955. auto v = std::make_unique<SchemaValidator>();
  956. SchemaValidatorContext context(schema);
  957. context.refs["#"] = v.get();
  958. v->loadSchema(context, schema);
  959. return std::move(v);
  960. }
  961. std::shared_ptr<Validator> makeSchemaValidator() {
  962. return schemaValidator.try_get();
  963. }
  964. } // namespace jsonschema
  965. } // namespace folly