Skip to content

Commit

Permalink
uri.resolve takes reference arg
Browse files Browse the repository at this point in the history
  • Loading branch information
danielaparker committed Dec 6, 2024
1 parent 35c1e67 commit 2fedb48
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 131 deletions.
4 changes: 2 additions & 2 deletions doc/ref/corelib/uri.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ Returns the decoded fragment part of this URI.
jsoncons::string_view encoded_fragment() const noexcept;
Returns the encoded fragment part of this URI.

uri resolve(const uri& base) const;
Resolves a uri reference against a base URI.
uri resolve(const uri& reference) const;
Resolve `reference` as a URI relative to this URI.

const std::string& string() const;
Returns a URI string.
Expand Down
79 changes: 42 additions & 37 deletions include/jsoncons/utility/uri.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,108 +354,113 @@ namespace jsoncons {
return string_view(uri_string_.data()+fragment_.first,(fragment_.second-fragment_.first));
}

uri resolve(const uri& base) const
bool has_fragment() const
{
return !encoded_fragment().empty();
}

uri resolve(const uri& reference) const
{
// This implementation uses the psuedo-code given in
// http://tools.ietf.org/html/rfc3986#section-5.2.2

if (is_absolute() && !is_opaque())
if (reference.is_absolute() && !reference.is_opaque())
{
return *this;
return reference;
}

if (is_opaque())
if (reference.is_opaque())
{
return *this;
return reference;
}

std::string userinfo, host, port, path, query, fragment;

if (!encoded_authority().empty())
if (!reference.encoded_authority().empty())
{
// g -> http://g
if (!this->encoded_userinfo().empty())
if (!reference.encoded_userinfo().empty())
{
userinfo = std::string(this->encoded_userinfo());
userinfo = std::string(reference.encoded_userinfo());
}

if (!this->host().empty())
if (!reference.host().empty())
{
host = std::string(this->host());
host = std::string(reference.host());
}

if (!this->port().empty())
if (!reference.port().empty())
{
port = std::string(this->port());
port = std::string(reference.port());
}

if (!this->encoded_path().empty())
if (!reference.encoded_path().empty())
{
path = remove_dot_segments(std::string(this->encoded_path()));
path = remove_dot_segments(std::string(reference.encoded_path()));
}

if (!this->encoded_query().empty())
if (!reference.encoded_query().empty())
{
query = std::string(this->encoded_query());
query = std::string(reference.encoded_query());
}
}
else
{
if (this->encoded_path().empty())
if (reference.encoded_path().empty())
{
if (!base.encoded_path().empty())
if (!encoded_path().empty())
{
path = std::string(base.encoded_path());
path = std::string(encoded_path());
}

if (!this->encoded_query().empty())
if (!reference.encoded_query().empty())
{
query = std::string(this->encoded_query());
query = std::string(reference.encoded_query());
}
else if (!base.encoded_query().empty())
else if (!encoded_query().empty())
{
query = std::string(base.encoded_query());
query = std::string(encoded_query());
}
}
else
{
if (this->encoded_path().front() == '/')
if (reference.encoded_path().front() == '/')
{
path = remove_dot_segments(std::string(this->encoded_path()));
path = remove_dot_segments(std::string(reference.encoded_path()));
}
else
{
path = merge_paths(base, *this);
path = merge_paths(*this, reference);
}

if (!this->encoded_query().empty())
if (!reference.encoded_query().empty())
{
query = std::string(this->encoded_query());
query = std::string(reference.encoded_query());
}
}

if (!base.encoded_userinfo().empty())
if (!encoded_userinfo().empty())
{
userinfo = std::string(base.encoded_userinfo());
userinfo = std::string(encoded_userinfo());
}

if (!base.host().empty())
if (!this->host().empty())
{
host = std::string(base.host());
host = std::string(this->host());
}

if (!base.port().empty())
if (!this->port().empty())
{
port = std::string(base.port());
port = std::string(this->port());
}
}

if (!this->encoded_fragment().empty())
if (!reference.encoded_fragment().empty())
{
fragment = std::string(this->encoded_fragment());
fragment = std::string(reference.encoded_fragment());
}

return uri(std::string(base.scheme()), userinfo, host, port, path, query, fragment);
return uri(std::string(scheme()), userinfo, host, port, path, query, fragment);
}

int compare(const uri& other) const
Expand Down
5 changes: 0 additions & 5 deletions include/jsoncons_ext/jsonschema/common/uri_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,6 @@ namespace jsonschema {
return identifier_;
}

uri_wrapper resolve(const uri_wrapper& uri) const
{
return uri.uri_.is_absolute() ? uri_wrapper{uri_.resolve(uri.uri_)} : *this;
}

int compare(const uri_wrapper& other) const
{
int result = uri_.compare(other.uri_);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,19 +288,18 @@ namespace draft201909 {
it = sch.find("$ref");
if (it != sch.object_range().end()) // this schema has a reference
{
uri_wrapper relative(it->value().template as<std::string>());
auto resolved = relative.resolve(uri_wrapper{ context.get_base_uri() });
validators.push_back(this->get_or_create_reference(sch, resolved));
uri relative{it->value().template as<std::string>()};
auto resolved = context.get_base_uri().resolve(relative);
validators.push_back(this->get_or_create_reference(sch, uri_wrapper{resolved}));
}

it = sch.find("$recursiveRef");
if (it != sch.object_range().end()) // this schema has a reference
{
uri_wrapper relative(it->value().template as<std::string>());
auto ref = relative.resolve(uri_wrapper
{ context.get_base_uri()});
auto orig = jsoncons::make_unique<recursive_ref_validator_type>(sch, ref.uri().base());
this->unresolved_refs_.emplace_back(ref.uri(), orig.get());
uri relative(it->value().template as<std::string>());
auto ref = context.get_base_uri().resolve(relative);
auto orig = jsoncons::make_unique<recursive_ref_validator_type>(sch, ref.base());
this->unresolved_refs_.emplace_back(ref, orig.get());
validators.push_back(std::move(orig));
}

Expand Down Expand Up @@ -500,13 +499,14 @@ namespace draft201909 {
auto it = sch.find("$id"); // If $id is found, this schema can be referenced by the id
if (it != sch.object_range().end())
{
uri_wrapper relative(it->value().template as<std::string>());
uri relative(it->value().template as<std::string>());
if (relative.has_fragment())
{
JSONCONS_THROW(schema_error("Draft 2019-09 does not allow $id with fragment"));
}
uri_wrapper new_uri = relative.resolve(uri_wrapper{ parent.get_base_uri() });
id = new_uri.uri();
auto resolved = parent.get_base_uri().resolve(relative);
id = resolved;
uri_wrapper new_uri{resolved};
//std::cout << "$id: " << id << ", " << new_uri.string() << "\n";
// Add it to the list if it is not already there
if (std::find(new_uris.begin(), new_uris.end(), new_uri) == new_uris.end())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,19 +288,19 @@ namespace draft202012 {
it = sch.find("$ref");
if (it != sch.object_range().end()) // this schema has a reference
{
uri_wrapper relative(it->value().template as<std::string>());
auto ref = relative.resolve(uri_wrapper{ context.get_base_uri() });
validators.push_back(this->get_or_create_reference(sch, ref));
uri relative(it->value().template as<std::string>());
auto ref = context.get_base_uri().resolve(relative) ;
validators.push_back(this->get_or_create_reference(sch, uri_wrapper(ref)));
}

it = sch.find("$dynamicRef");
if (it != sch.object_range().end()) // this schema has a reference
{
std::string value = it->value().template as<std::string>();
uri_wrapper relative(value);
auto ref = relative.resolve(uri_wrapper{ context.get_base_uri() });
auto orig = jsoncons::make_unique<dynamic_ref_validator_type>(sch, ref.uri().base(), ref);
this->unresolved_refs_.emplace_back(ref.uri(), orig.get());
uri relative(value);
auto ref = context.get_base_uri().resolve(relative) ;
auto orig = jsoncons::make_unique<dynamic_ref_validator_type>(sch, ref.base(), uri_wrapper{ref});
this->unresolved_refs_.emplace_back(ref, orig.get());
validators.push_back(std::move(orig));
}

Expand Down Expand Up @@ -555,13 +555,14 @@ namespace draft202012 {
if (it != sch.object_range().end())
{
std::string str = it->value().template as<std::string>();
uri_wrapper relative(str);
uri relative(str);
if (relative.has_fragment())
{
JSONCONS_THROW(schema_error(str + ": Draft 2019-09 does not allow $id with fragment"));
}
uri_wrapper new_uri = relative.resolve(uri_wrapper{ parent.get_base_uri() });
id = new_uri.uri();
auto resolved = parent.get_base_uri().resolve(relative);
id = resolved;
uri_wrapper new_uri{resolved};
//std::cout << "$id: " << id << ", " << new_uri.string() << "\n";
// Add it to the list if it is not already there
if (std::find(new_uris.begin(), new_uris.end(), new_uri) == new_uris.end())
Expand Down
13 changes: 7 additions & 6 deletions include/jsoncons_ext/jsonschema/draft4/schema_builder_4.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ namespace draft4 {
}

Json default_value{ jsoncons::null_type() };
uri_wrapper relative(it->value().template as<std::string>());
auto id = relative.resolve(uri_wrapper{ context.get_base_uri() });
validators.push_back(this->get_or_create_reference(sch, id));
uri relative(it->value().template as<std::string>());
auto id = context.get_base_uri().resolve(relative);
validators.push_back(this->get_or_create_reference(sch, uri_wrapper{id}));
schema_validator_ptr = jsoncons::make_unique<object_schema_validator<Json>>(
new_context.get_base_uri(), context.id(),
std::move(validators), std::move(defs), std::move(default_value));
Expand Down Expand Up @@ -386,9 +386,10 @@ namespace draft4 {
auto it = sch.find("id"); // If id is found, this schema can be referenced by the id
if (it != sch.object_range().end())
{
uri_wrapper relative(it->value().template as<std::string>());
uri_wrapper new_uri = relative.resolve(uri_wrapper{ parent.get_base_uri() });
id = new_uri.uri();
uri relative(it->value().template as<std::string>());
auto resolved = parent.get_base_uri().resolve(relative);
id = resolved;
uri_wrapper new_uri{ resolved };
//std::cout << "id: " << id << ", " << new_uri.string() << "\n";
// Add it to the list if it is not already there
if (std::find(new_uris.begin(), new_uris.end(), new_uri) == new_uris.end())
Expand Down
14 changes: 8 additions & 6 deletions include/jsoncons_ext/jsonschema/draft6/schema_builder_6.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,9 @@ namespace draft6 {
}

Json default_value{ jsoncons::null_type() };
uri_wrapper relative(it->value().template as<std::string>());
auto id = relative.resolve(uri_wrapper{ context.get_base_uri() });
validators.push_back(this->get_or_create_reference(sch, id));
uri relative(it->value().template as<std::string>());
auto id = context.get_base_uri().resolve(relative) ;
validators.push_back(this->get_or_create_reference(sch, uri_wrapper{id}));
schema_validator_ptr = jsoncons::make_unique<object_schema_validator<Json>>(
new_context.get_base_uri(), context.id(),
std::move(validators), std::move(defs), std::move(default_value));
Expand Down Expand Up @@ -338,9 +338,11 @@ namespace draft6 {
auto it = sch.find("$id"); // If $id is found, this schema can be referenced by the id
if (it != sch.object_range().end())
{
uri_wrapper relative(it->value().template as<std::string>());
uri_wrapper new_uri = relative.resolve(uri_wrapper{ parent.get_base_uri() });
id = new_uri.uri();
uri relative(it->value().template as<std::string>());
auto resolved = parent.get_base_uri().resolve(relative);
id = resolved;
uri_wrapper new_uri{resolved};

//std::cout << "$id: " << id << ", " << new_uri.string() << "\n";
// Add it to the list if it is not already there
if (std::find(new_uris.begin(), new_uris.end(), new_uri) == new_uris.end())
Expand Down
14 changes: 8 additions & 6 deletions include/jsoncons_ext/jsonschema/draft7/schema_builder_7.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,9 @@ namespace draft7 {
}

Json default_value{ jsoncons::null_type() };
uri_wrapper relative(it->value().template as<std::string>());
auto id = relative.resolve(uri_wrapper{ context.get_base_uri() });
validators.push_back(this->get_or_create_reference(sch, id));
uri relative(it->value().template as<std::string>());
auto id = context.get_base_uri().resolve(relative);
validators.push_back(this->get_or_create_reference(sch, uri_wrapper{id}));
schema_validator_ptr = jsoncons::make_unique<object_schema_validator<Json>>(
new_context.get_base_uri(), context.id(),
std::move(validators), std::move(defs), std::move(default_value));
Expand Down Expand Up @@ -371,11 +371,13 @@ namespace draft7 {
auto it = sch.find("$id"); // If $id is found, this schema can be referenced by the id
if (it != sch.object_range().end())
{
uri_wrapper relative(it->value().template as<std::string>());
uri_wrapper new_uri = relative.resolve(uri_wrapper{ parent.get_base_uri() });
id = new_uri.uri();
uri relative(it->value().template as<std::string>());
auto resolved = parent.get_base_uri().resolve(relative);
id = resolved;
//std::cout << "$id: " << id << ", " << new_uri.string() << "\n";
// Add it to the list if it is not already there

uri_wrapper new_uri{resolved};
if (std::find(new_uris.begin(), new_uris.end(), new_uri) == new_uris.end())
{
new_uris.emplace_back(new_uri);
Expand Down
Loading

0 comments on commit 2fedb48

Please sign in to comment.