add content-checker-callback
Used when contentEncoding or mediaType attributes are present on a string-value.
This commit is contained in:
parent
32af07ce19
commit
5ef4f903af
@ -105,6 +105,7 @@ class root_schema : public schema
|
|||||||
{
|
{
|
||||||
schema_loader loader_;
|
schema_loader loader_;
|
||||||
format_checker format_check_;
|
format_checker format_check_;
|
||||||
|
content_checker content_check_;
|
||||||
|
|
||||||
std::shared_ptr<schema> root_;
|
std::shared_ptr<schema> root_;
|
||||||
|
|
||||||
@ -128,10 +129,18 @@ class root_schema : public schema
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
root_schema(schema_loader &&loader,
|
root_schema(schema_loader &&loader,
|
||||||
format_checker &&format)
|
format_checker &&format,
|
||||||
: schema(this), loader_(std::move(loader)), format_check_(std::move(format)) {}
|
content_checker &&content)
|
||||||
|
|
||||||
|
: schema(this),
|
||||||
|
loader_(std::move(loader)),
|
||||||
|
format_check_(std::move(format)),
|
||||||
|
content_check_(std::move(content))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
format_checker &format_check() { return format_check_; }
|
format_checker &format_check() { return format_check_; }
|
||||||
|
content_checker &content_check() { return content_check_; }
|
||||||
|
|
||||||
void insert(const json_uri &uri, const std::shared_ptr<schema> &s)
|
void insert(const json_uri &uri, const std::shared_ptr<schema> &s)
|
||||||
{
|
{
|
||||||
@ -461,8 +470,24 @@ class type_schema : public schema
|
|||||||
else_->validate(ptr, instance, patch, e);
|
else_->validate(ptr, instance, patch, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// special treatment
|
||||||
|
if (instance.type() == json::value_t::string && std::get<0>(content_)) {
|
||||||
|
if (root_->content_check() == nullptr)
|
||||||
|
e.error(ptr, instance, std::string("a content checker was not provided but a contentEncoding or contentMediaType for this string have been present: '") + std::get<1>(content_) + "' '" + std::get<2>(content_) + "'");
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
root_->content_check()(std::get<1>(content_), std::get<2>(content_), instance);
|
||||||
|
} catch (const std::exception &ex) {
|
||||||
|
e.error(ptr, instance, std::string("content-checking failed: ") + ex.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::tuple<bool, std::string, std::string> content_{false, "", ""};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
type_schema(json &sch,
|
type_schema(json &sch,
|
||||||
root_schema *root,
|
root_schema *root,
|
||||||
@ -583,6 +608,20 @@ public:
|
|||||||
}
|
}
|
||||||
sch.erase(attr);
|
sch.erase(attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attr = sch.find("contentEncoding");
|
||||||
|
if (attr != sch.end()) {
|
||||||
|
std::get<0>(content_) = true;
|
||||||
|
std::get<1>(content_) = attr.value().get<std::string>();
|
||||||
|
sch.erase(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
attr = sch.find("contentMediaType");
|
||||||
|
if (attr != sch.end()) {
|
||||||
|
std::get<0>(content_) = true;
|
||||||
|
std::get<2>(content_) = attr.value().get<std::string>();
|
||||||
|
sch.erase(attr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1212,19 +1251,33 @@ namespace json_schema
|
|||||||
{
|
{
|
||||||
|
|
||||||
json_validator::json_validator(schema_loader loader,
|
json_validator::json_validator(schema_loader loader,
|
||||||
format_checker format)
|
format_checker format,
|
||||||
: root_(std::unique_ptr<root_schema>(new root_schema(std::move(loader), std::move(format))))
|
content_checker content)
|
||||||
|
: root_(std::unique_ptr<root_schema>(new root_schema(std::move(loader),
|
||||||
|
std::move(format),
|
||||||
|
std::move(content))))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
json_validator::json_validator(const json &schema, schema_loader loader, format_checker format)
|
json_validator::json_validator(const json &schema,
|
||||||
: json_validator(std::move(loader), std::move(format))
|
schema_loader loader,
|
||||||
|
format_checker format,
|
||||||
|
content_checker content)
|
||||||
|
: json_validator(std::move(loader),
|
||||||
|
std::move(format),
|
||||||
|
std::move(content))
|
||||||
{
|
{
|
||||||
set_root_schema(schema);
|
set_root_schema(schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
json_validator::json_validator(json &&schema, schema_loader loader, format_checker format)
|
json_validator::json_validator(json &&schema,
|
||||||
: json_validator(std::move(loader), std::move(format))
|
schema_loader loader,
|
||||||
|
format_checker format,
|
||||||
|
content_checker content)
|
||||||
|
|
||||||
|
: json_validator(std::move(loader),
|
||||||
|
std::move(format),
|
||||||
|
std::move(content))
|
||||||
{
|
{
|
||||||
set_root_schema(std::move(schema));
|
set_root_schema(std::move(schema));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -133,6 +133,7 @@ extern json draft7_schema_builtin;
|
|||||||
|
|
||||||
typedef std::function<void(const json_uri & /*id*/, json & /*value*/)> schema_loader;
|
typedef std::function<void(const json_uri & /*id*/, json & /*value*/)> schema_loader;
|
||||||
typedef std::function<void(const std::string & /*format*/, const std::string & /*value*/)> format_checker;
|
typedef std::function<void(const std::string & /*format*/, const std::string & /*value*/)> format_checker;
|
||||||
|
typedef std::function<void(const std::string & /*contentEncoding*/, const std::string & /*contentMediaType*/, const json & /*instance*/)> content_checker;
|
||||||
|
|
||||||
// Interface for validation error handlers
|
// Interface for validation error handlers
|
||||||
class JSON_SCHEMA_VALIDATOR_API error_handler
|
class JSON_SCHEMA_VALIDATOR_API error_handler
|
||||||
@ -168,10 +169,10 @@ class JSON_SCHEMA_VALIDATOR_API json_validator
|
|||||||
std::unique_ptr<root_schema> root_;
|
std::unique_ptr<root_schema> root_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
json_validator(schema_loader = nullptr, format_checker = nullptr);
|
json_validator(schema_loader = nullptr, format_checker = nullptr, content_checker = nullptr);
|
||||||
|
|
||||||
json_validator(const json &, schema_loader = nullptr, format_checker = nullptr);
|
json_validator(const json &, schema_loader = nullptr, format_checker = nullptr, content_checker = nullptr);
|
||||||
json_validator(json &&, schema_loader = nullptr, format_checker = nullptr);
|
json_validator(json &&, schema_loader = nullptr, format_checker = nullptr, content_checker = nullptr);
|
||||||
|
|
||||||
json_validator(json_validator &&);
|
json_validator(json_validator &&);
|
||||||
json_validator &operator=(json_validator &&);
|
json_validator &operator=(json_validator &&);
|
||||||
|
|||||||
@ -50,7 +50,6 @@ if(JSON_SCHEMA_TEST_SUITE_PATH)
|
|||||||
# some optional tests will fail
|
# some optional tests will fail
|
||||||
set_tests_properties(
|
set_tests_properties(
|
||||||
JSON-Suite::Optional::bignum
|
JSON-Suite::Optional::bignum
|
||||||
JSON-Suite::Optional::content
|
|
||||||
JSON-Suite::Optional::zeroTerminatedFloats
|
JSON-Suite::Optional::zeroTerminatedFloats
|
||||||
JSON-Suite::Optional::non-bmp-regex
|
JSON-Suite::Optional::non-bmp-regex
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,50 @@ static void loader(const json_uri &uri, json &schema)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// from here
|
||||||
|
// https://stackoverflow.com/a/34571089/880584
|
||||||
|
static std::string base64_decode(const std::string &in)
|
||||||
|
{
|
||||||
|
std::string out;
|
||||||
|
|
||||||
|
std::vector<int> T(256, -1);
|
||||||
|
for (int i = 0; i < 64; i++)
|
||||||
|
T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
|
||||||
|
|
||||||
|
unsigned val = 0;
|
||||||
|
int valb = -8;
|
||||||
|
for (uint8_t c : in) {
|
||||||
|
if (c == '=')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (T[c] == -1) {
|
||||||
|
throw std::invalid_argument("base64-decode: unexpected character in encode string: '" + std::string(1, c) + "'");
|
||||||
|
}
|
||||||
|
val = (val << 6) + T[c];
|
||||||
|
valb += 6;
|
||||||
|
if (valb >= 0) {
|
||||||
|
out.push_back(char((val >> valb) & 0xFF));
|
||||||
|
valb -= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void content(const std::string &contentEncoding, const std::string &contentMediaType, const json &instance)
|
||||||
|
{
|
||||||
|
std::string content = instance;
|
||||||
|
|
||||||
|
if (contentEncoding == "base64")
|
||||||
|
content = base64_decode(instance);
|
||||||
|
else if (contentEncoding != "")
|
||||||
|
throw std::invalid_argument("unable to check for contentEncoding '" + contentEncoding + "'");
|
||||||
|
|
||||||
|
if (contentMediaType == "application/json")
|
||||||
|
auto dummy = json::parse(content); // throws if conversion fails
|
||||||
|
else if (contentMediaType != "")
|
||||||
|
throw std::invalid_argument("unable to check for contentMediaType '" + contentMediaType + "'");
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
json validation; // a validation case following the JSON-test-suite-schema
|
json validation; // a validation case following the JSON-test-suite-schema
|
||||||
@ -62,7 +106,8 @@ int main(void)
|
|||||||
const auto &schema = test_group["schema"];
|
const auto &schema = test_group["schema"];
|
||||||
|
|
||||||
json_validator validator(loader,
|
json_validator validator(loader,
|
||||||
nlohmann::json_schema::default_string_format_check);
|
nlohmann::json_schema::default_string_format_check,
|
||||||
|
content);
|
||||||
|
|
||||||
validator.set_root_schema(schema);
|
validator.set_root_schema(schema);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user