srctree

Robin Linden parent 0c05db0c 17c47303
url: Allow overriding the error-handling

This enables us to e.g. display parse-errors in the UI and other thingsthat aren't just printing all errors to the console.

inlinesplit
url/url.cpp added: 48, removed: 9, total 39
@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2023 David Zero <zero-one@zer0-one.net>
// SPDX-FileCopyrightText: 2023 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
@@ -296,11 +297,17 @@ Origin Url::origin() const {
}
 
void UrlParser::validation_error(ValidationError err) const {
spdlog::warn("url: InputPos: {}, ParserState: {}, Validation Error: {} {}",
current_pos(),
std::to_underlying(state_),
std::to_underlying(err),
validation_error_str.at(err));
on_error_(err);
}
 
UrlParser::UrlParser() : util::BaseParser("") {
set_on_error([this](ValidationError e) {
spdlog::warn("url: InputPos: {}, ParserState: {}, Validation Error: {} {}",
current_pos(),
std::to_underlying(state_),
std::to_underlying(e),
validation_error_str.at(e));
});
}
 
// https://url.spec.whatwg.org/#concept-url-parser
 
url/url.h added: 48, removed: 9, total 39
@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2023 David Zero <zero-one@zer0-one.net>
// SPDX-FileCopyrightText: 2023 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
@@ -10,10 +11,12 @@
 
#include <array>
#include <cstdint>
#include <functional>
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <variant>
 
namespace url {
@@ -109,7 +112,7 @@ struct Url {
// This parser is current with the WHATWG URL specification as of 27 September 2023
class UrlParser final : util::BaseParser {
public:
UrlParser() : BaseParser{""} {}
UrlParser();
 
std::optional<Url> parse(std::string input, std::optional<Url> base = std::nullopt);
 
@@ -148,6 +151,8 @@ public:
FileInvalidWindowsDriveLetterHost
};
 
void set_on_error(std::function<void(ValidationError)> on_error) { on_error_ = std::move(on_error); }
 
private:
enum class ParserState {
SchemeStart,
@@ -240,6 +245,8 @@ private:
bool at_sign_seen_ = false;
bool inside_brackets_ = false;
bool password_token_seen_ = false;
 
std::function<void(ValidationError)> on_error_;
};
 
} // namespace url
 
url/url_test.cpp added: 48, removed: 9, total 39
@@ -15,7 +15,26 @@
#include <iostream>
#include <optional>
#include <regex>
#include <utility>
#include <variant>
#include <vector>
 
namespace {
 
struct ParseResult {
std::optional<url::Url> url;
std::vector<url::UrlParser::ValidationError> errors;
};
 
ParseResult parse_url(std::string input, std::optional<url::Url> base = std::nullopt) {
std::vector<url::UrlParser::ValidationError> errors;
url::UrlParser p;
p.set_on_error([&errors](url::UrlParser::ValidationError e) { errors.push_back(e); });
std::optional<url::Url> url = p.parse(std::move(input), std::move(base));
return {std::move(url), std::move(errors)};
}
 
} // namespace
 
int main() {
url::Url const base{"https",
@@ -671,6 +690,12 @@ int main() {
etest::expect_eq(url->serialize_path(), "/usr/bin/emacs");
});
 
etest::test("URL parsing: non-relative url w/o scheme", [] {
auto [url, errors] = parse_url("//example.com");
etest::expect_eq(url, std::nullopt);
etest::expect_eq(errors, std::vector{url::UrlParser::ValidationError::MissingSchemeNonRelativeUrl});
});
 
etest::test("Web Platform Tests", [] {
url::UrlParser p;