diff --git a/Userland/Libraries/LibCore/Proxy.h b/Userland/Libraries/LibCore/Proxy.h index d2fe8f7551..6b56a0c3df 100644 --- a/Userland/Libraries/LibCore/Proxy.h +++ b/Userland/Libraries/LibCore/Proxy.h @@ -7,7 +7,9 @@ #pragma once #include +#include #include +#include #include namespace Core { @@ -22,6 +24,30 @@ struct ProxyData { int port { 0 }; bool operator==(ProxyData const& other) const = default; + + static ErrorOr parse_url(URL const& url) + { + if (!url.is_valid()) + return Error::from_string_literal("Invalid proxy URL"); + + ProxyData proxy_data; + if (url.scheme() != "socks5") + return Error::from_string_literal("Unsupported proxy type"); + + proxy_data.type = ProxyData::Type::SOCKS5; + + auto host_ipv4 = IPv4Address::from_string(url.host()); + if (!host_ipv4.has_value()) + return Error::from_string_literal("Invalid proxy host, must be an IPv4 address"); + proxy_data.host_ipv4 = host_ipv4->to_u32(); + + auto port = url.port(); + if (!port.has_value()) + return Error::from_string_literal("Invalid proxy, must have a port"); + proxy_data.port = *port; + + return proxy_data; + } }; } diff --git a/Userland/Utilities/pro.cpp b/Userland/Utilities/pro.cpp index d68a8ba950..123b1d11fe 100644 --- a/Userland/Utilities/pro.cpp +++ b/Userland/Utilities/pro.cpp @@ -151,6 +151,7 @@ ErrorOr serenity_main(Main::Arguments arguments) bool save_at_provided_name = false; bool should_follow_url = false; char const* data = nullptr; + StringView proxy_spec; String method = "GET"; HashMap request_headers; @@ -175,6 +176,7 @@ ErrorOr serenity_main(Main::Arguments arguments) request_headers.set(header.substring_view(0, split.value()), header.substring_view(split.value() + 1)); return true; } }); + args_parser.add_option(proxy_spec, "Specify a proxy server to use for this request (proto://ip:port)", "proxy", 'p', "proxy"); args_parser.add_positional_argument(url_str, "URL to download from", "url"); args_parser.parse(arguments); @@ -189,6 +191,8 @@ ErrorOr serenity_main(Main::Arguments arguments) return 1; } + Core::ProxyData proxy_data = TRY(Core::ProxyData::parse_url(proxy_spec)); + Core::EventLoop loop; bool received_actual_headers = false; bool should_save_stream_data = false; @@ -287,7 +291,7 @@ ErrorOr serenity_main(Main::Arguments arguments) Core::deferred_invoke([&, was_following_url, url = location.value()] { warnln("{}Following to {}", was_following_url ? "" : "\n", url); - request = protocol_client->start_request(method, url, request_headers, ReadonlyBytes {}); + request = protocol_client->start_request(method, url, request_headers, ReadonlyBytes {}, proxy_data); setup_request(); }); } @@ -309,7 +313,7 @@ ErrorOr serenity_main(Main::Arguments arguments) request->stream_into(output_stream); }; - request = protocol_client->start_request(method, url, request_headers, data ? StringView { data }.bytes() : ReadonlyBytes {}); + request = protocol_client->start_request(method, url, request_headers, data ? StringView { data }.bytes() : ReadonlyBytes {}, proxy_data); setup_request(); dbgln("started request with id {}", request->id());