ladybird/Libraries/LibWeb/WebDriver/Proxy.cpp
2025-02-20 19:27:51 -05:00

136 lines
5.8 KiB
C++

/*
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/JsonValue.h>
#include <LibURL/Parser.h>
#include <LibURL/URL.h>
#include <LibWeb/WebDriver/Proxy.h>
namespace Web::WebDriver {
// https://w3c.github.io/webdriver/#dfn-has-proxy-configuration
// An endpoint node has an associated has proxy configuration flag that indicates whether the proxy is already configured.
// The default value of the flag is true if the endpoint doesn't support proxy configuration, or false otherwise.
static constexpr bool s_default_has_proxy_configuration = true;
static bool s_has_proxy_configuration = s_default_has_proxy_configuration;
bool has_proxy_configuration()
{
return s_has_proxy_configuration;
}
void set_has_proxy_configuration(bool has_proxy_configuration)
{
s_has_proxy_configuration = has_proxy_configuration;
}
void reset_has_proxy_configuration()
{
s_has_proxy_configuration = s_default_has_proxy_configuration;
}
// https://w3c.github.io/webdriver/#dfn-proxy-configuration
static ErrorOr<void, Error> validate_proxy_item(StringView key, JsonValue const& value)
{
if (key == "proxyType"sv) {
if (!value.is_string())
return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'proxyType' must be a string"sv);
if (!value.as_string().is_one_of("pac"sv, "direct"sv, "autodetect"sv, "system"sv, "manual"sv))
return Error::from_code(ErrorCode::InvalidArgument, "Invalid 'proxyType' value"sv);
return {};
}
if (key == "proxyAutoconfigUrl"sv) {
if (!value.is_string())
return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'proxyAutoconfigUrl' must be a string"sv);
if (auto url = URL::Parser::basic_parse(value.as_string()); !url.has_value())
return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'proxyAutoconfigUrl' must be a valid URL"sv);
return {};
}
if (key == "ftpProxy"sv) {
if (!value.is_string())
return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'ftpProxy' must be a string"sv);
if (auto url = URL::Parser::basic_parse(value.as_string()); !url.has_value() || url->scheme() != "ftp"sv)
return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'ftpProxy' must be a valid FTP URL"sv);
return {};
}
if (key == "httpProxy"sv) {
if (!value.is_string())
return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'httpProxy' must be a string"sv);
if (auto url = URL::Parser::basic_parse(value.as_string()); !url.has_value() || url->scheme() != "http"sv)
return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'httpProxy' must be a valid HTTP URL"sv);
return {};
}
if (key == "noProxy"sv) {
if (!value.is_array())
return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'noProxy' must be a list"sv);
TRY(value.as_array().try_for_each([&](JsonValue const& item) -> ErrorOr<void, Error> {
if (!item.is_string())
return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'noProxy' must be a list of strings"sv);
return {};
}));
return {};
}
if (key == "sslProxy"sv) {
if (!value.is_string())
return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'sslProxy' must be a string"sv);
if (auto url = URL::Parser::basic_parse(value.as_string()); !url.has_value() || url->scheme() != "https"sv)
return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'sslProxy' must be a valid HTTPS URL"sv);
return {};
}
if (key == "socksProxy"sv) {
if (!value.is_string())
return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'proxyAutoconfigUrl' must be a string"sv);
if (auto url = URL::Parser::basic_parse(value.as_string()); !url.has_value())
return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'proxyAutoconfigUrl' must be a valid URL"sv);
return {};
}
if (key == "socksVersion"sv) {
if (!value.is_integer<u8>())
return Error::from_code(ErrorCode::InvalidArgument, "Proxy configuration item 'socksVersion' must be an integer in the range [0, 255]"sv);
return {};
}
return Error::from_code(ErrorCode::InvalidArgument, "Invalid proxy configuration item"sv);
}
// https://w3c.github.io/webdriver/#dfn-deserialize-as-a-proxy
ErrorOr<JsonObject, Error> deserialize_as_a_proxy(JsonValue const& parameter)
{
// 1. If parameter is not a JSON Object return an error with error code invalid argument.
if (!parameter.is_object())
return Error::from_code(ErrorCode::InvalidArgument, "Capability proxy must be an object"sv);
// 2. Let proxy be a new, empty proxy configuration object.
JsonObject proxy;
// 3. For each enumerable own property in parameter run the following substeps:
TRY(parameter.as_object().try_for_each_member([&](String const& key, JsonValue const& value) -> ErrorOr<void, Error> {
// 1. Let key be the name of the property.
// 2. Let value be the result of getting a property named name from capability.
// 3. If there is no matching key for key in the proxy configuration table return an error with error code invalid argument.
// 4. If value is not one of the valid values for that key, return an error with error code invalid argument.
TRY(validate_proxy_item(key, value));
// 5. Set a property key to value on proxy.
proxy.set(key, value);
return {};
}));
return proxy;
}
}