@@ -32,51 +32,7 @@ void normalize(Uri &uri) {
}
}
// NOLINTNEXTLINE(misc-no-recursion)
[[nodiscard]] bool complete_from_base_if_needed(Uri &uri, Uri const &base) {
if (uri.scheme.empty() && uri.authority.host.empty() && uri.path.starts_with('/')) {
// Origin-relative.
auto new_uri = Uri::parse(fmt::format("{}://{}{}", base.scheme, base.authority.host, uri.uri));
if (!new_uri) {
return false;
}
uri = *std::move(new_uri);
} else if (uri.scheme.empty() && uri.authority.host.empty() && !uri.path.empty()) {
// https://url.spec.whatwg.org/#path-relative-url-string
if (base.path == "/") {
auto new_uri = Uri::parse(fmt::format("{}/{}", base.uri, uri.uri));
if (!new_uri) {
return false;
}
uri = *std::move(new_uri);
} else {
auto end_of_last_path_segment = base.uri.find_last_of('/');
auto new_uri = Uri::parse(fmt::format("{}/{}", base.uri.substr(0, end_of_last_path_segment), uri.uri));
if (!new_uri) {
return false;
}
uri = *std::move(new_uri);
}
} else if (uri.scheme.empty() && !uri.authority.host.empty() && uri.uri.starts_with("//")) {
// Scheme-relative.
auto new_uri = Uri::parse(fmt::format("{}:{}", base.scheme, uri.uri));
if (!new_uri) {
return false;
}
uri = *std::move(new_uri);
}
return true;
}
} // namespace
// NOLINTNEXTLINE(misc-no-recursion)
std::optional<Uri> Uri::parse(std::string uristr, std::optional<std::reference_wrapper<Uri const>> base_uri) {
std::optional<Uri> parse_uri(std::string uristr) {
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86164
// Fuzz-testing w/ libstdc++13 still breaks the stack if 2048 characters are allowed.
if (uristr.size() > 1024) {
@@ -128,10 +84,59 @@ std::optional<Uri> Uri::parse(std::string uristr, std::optional<std::reference_w
normalize(uri);
if (base_uri) {
if (!complete_from_base_if_needed(uri, base_uri->get())) {
return std::nullopt;
return uri;
}
[[nodiscard]] bool complete_from_base_if_needed(Uri &uri, Uri const &base) {
if (uri.scheme.empty() && uri.authority.host.empty() && uri.path.starts_with('/')) {
// Origin-relative.
auto new_uri = parse_uri(fmt::format("{}://{}{}", base.scheme, base.authority.host, uri.uri));
if (!new_uri) {
return false;
}
uri = *std::move(new_uri);
} else if (uri.scheme.empty() && uri.authority.host.empty() && !uri.path.empty()) {
// https://url.spec.whatwg.org/#path-relative-url-string
if (base.path == "/") {
auto new_uri = parse_uri(fmt::format("{}/{}", base.uri, uri.uri));
if (!new_uri) {
return false;
}
uri = *std::move(new_uri);
} else {
auto end_of_last_path_segment = base.uri.find_last_of('/');
auto new_uri = parse_uri(fmt::format("{}/{}", base.uri.substr(0, end_of_last_path_segment), uri.uri));
if (!new_uri) {
return false;
}
uri = *std::move(new_uri);
}
} else if (uri.scheme.empty() && !uri.authority.host.empty() && uri.uri.starts_with("//")) {
// Scheme-relative.
auto new_uri = parse_uri(fmt::format("{}:{}", base.scheme, uri.uri));
if (!new_uri) {
return false;
}
uri = *std::move(new_uri);
}
return true;
}
} // namespace
std::optional<Uri> Uri::parse(std::string uristr, std::optional<std::reference_wrapper<Uri const>> base_uri) {
auto uri = parse_uri(std::move(uristr));
if (!uri) {
return uri;
}
if (base_uri && !complete_from_base_if_needed(*uri, base_uri->get())) {
return std::nullopt;
}
return uri;