From 2c5b7f94d17dbd8df1e015ae2f89844ac1f10602 Mon Sep 17 00:00:00 2001 From: Alexander Terentyev Date: Tue, 11 Mar 2025 08:32:18 +1000 Subject: [PATCH] feat: proxy support for web-connections (#5038) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feature: proxy support for web-connections * forgotten changes * fix code-styles * –Documentation for new setting "proxy-url" * Create property proxyUrl for class tr_web. Lazy creation of tr_web object in tr_session after loaded settings from file * Update docs/Editing-Configuration-Files.md Simplify the documentation text Co-authored-by: ThinkChaos * Fix merge error * Fix merge error. * Simplify tr_web's lifecycle. Fix error. Rename quark to sneak_case-style * Fix parameter value test --------- Co-authored-by: ThinkChaos Co-authored-by: Charles Kerr --- docs/Editing-Configuration-Files.md | 1 + libtransmission/quark.cc | 1 + libtransmission/quark.h | 1 + libtransmission/session.cc | 5 +++++ libtransmission/session.h | 3 +++ libtransmission/web.cc | 5 +++++ libtransmission/web.h | 6 ++++++ 7 files changed, 22 insertions(+) diff --git a/docs/Editing-Configuration-Files.md b/docs/Editing-Configuration-Files.md index 62038bce7..6811fae96 100644 --- a/docs/Editing-Configuration-Files.md +++ b/docs/Editing-Configuration-Files.md @@ -81,6 +81,7 @@ Here is a sample of the three basic types: respectively Boolean, Number and Stri * **message-level:** Number (0 = None, 1 = Critical, 2 = Error, 3 = Warn, 4 = Info, 5 = Debug, 6 = Trace; default = 4) Set verbosity of Transmission's log messages. * **pex-enabled:** Boolean (default = true) Enable [Peer Exchange (PEX)](https://en.wikipedia.org/wiki/Peer_exchange). * **pidfile:** String Path to file in which daemon PID will be stored (_transmission-daemon only_) + * **proxy_url:** String (default = "") Proxy for HTTP(S) requests (for example, requests to tracker). Format `[scheme]://[host]:[port]`, where `scheme` is one of: `http`, `https`, `socks4`, `socks4h`, `socks5`, `socks5h`. If unspecified, or empty, no proxy is used. For more information see [curl proxy documentation](https://curl.se/libcurl/c/CURLOPT_PROXY.html) * **scrape-paused-torrents-enabled:** Boolean (default = true) * **script-torrent-added-enabled:** Boolean (default = false) Run a script when a torrent is added to Transmission. Environmental variables are passed in as detailed on the [Scripts](./Scripts.md) page. * **script-torrent-added-filename:** String (default = "") Path to script. diff --git a/libtransmission/quark.cc b/libtransmission/quark.cc index 24e54f2f6..adb7b87c8 100644 --- a/libtransmission/quark.cc +++ b/libtransmission/quark.cc @@ -263,6 +263,7 @@ auto constexpr MyStatic = std::array{ "private"sv, "progress"sv, "prompt-before-exit"sv, + "proxy_url"sv, "queue-move-bottom"sv, "queue-move-down"sv, "queue-move-top"sv, diff --git a/libtransmission/quark.h b/libtransmission/quark.h index 673e902f7..99a35c41d 100644 --- a/libtransmission/quark.h +++ b/libtransmission/quark.h @@ -265,6 +265,7 @@ enum TR_KEY_private, TR_KEY_progress, TR_KEY_prompt_before_exit, + TR_KEY_proxy_url, TR_KEY_queue_move_bottom, TR_KEY_queue_move_down, TR_KEY_queue_move_top, diff --git a/libtransmission/session.cc b/libtransmission/session.cc index f0dda4b4e..72ec13d0c 100644 --- a/libtransmission/session.cc +++ b/libtransmission/session.cc @@ -349,6 +349,11 @@ size_t tr_session::WebMediator::clamp(int torrent_id, size_t byte_count) const return tor == nullptr ? 0U : tor->bandwidth().clamp(TR_DOWN, byte_count); } +std::optional tr_session::WebMediator::proxyUrl() const +{ + return session_->settings_.proxy_url; +} + void tr_session::WebMediator::run(tr_web::FetchDoneFunc&& func, tr_web::FetchResponse&& response) const { session_->run_in_session_thread(std::move(func), std::move(response)); diff --git a/libtransmission/session.h b/libtransmission/session.h index 10410e940..bbec42ee2 100644 --- a/libtransmission/session.h +++ b/libtransmission/session.h @@ -263,6 +263,7 @@ private: [[nodiscard]] std::optional bind_address_V6() const override; [[nodiscard]] std::optional userAgent() const override; [[nodiscard]] size_t clamp(int torrent_id, size_t byte_count) const override; + [[nodiscard]] std::optional proxyUrl() const override; [[nodiscard]] time_t now() const override; // runs the tr_web::fetch response callback in the libtransmission thread void run(tr_web::FetchDoneFunc&& func, tr_web::FetchResponse&& response) const override; @@ -436,6 +437,7 @@ public: std::string script_torrent_added_filename; std::string script_torrent_done_filename; std::string script_torrent_done_seeding_filename; + std::string proxy_url; tr_encryption_mode encryption_mode = TR_ENCRYPTION_PREFERRED; tr_log_level log_level = TR_LOG_INFO; tr_mode_t umask = 022; @@ -481,6 +483,7 @@ public: { TR_KEY_port_forwarding_enabled, &port_forwarding_enabled }, { TR_KEY_preallocation, &preallocation_mode }, { TR_KEY_preferred_transport, &preferred_transport }, + { TR_KEY_proxy_url, &proxy_url }, { TR_KEY_queue_stalled_enabled, &queue_stalled_enabled }, { TR_KEY_queue_stalled_minutes, &queue_stalled_minutes }, { TR_KEY_ratio_limit, &ratio_limit }, diff --git a/libtransmission/web.cc b/libtransmission/web.cc index 303832f44..7c8ff789b 100644 --- a/libtransmission/web.cc +++ b/libtransmission/web.cc @@ -621,6 +621,11 @@ public: (void)curl_easy_setopt(e, CURLOPT_COOKIEFILE, file.c_str()); } + if (auto const& proxyUrl = mediator.proxyUrl().value_or(""); !std::empty(proxyUrl)) + { + (void)curl_easy_setopt(e, CURLOPT_PROXY, proxyUrl.data()); + } + if (auto const& range = task.range(); range) { /* don't bother asking the server to compress webseed fragments */ diff --git a/libtransmission/web.h b/libtransmission/web.h index 363094440..045865cf1 100644 --- a/libtransmission/web.h +++ b/libtransmission/web.h @@ -149,6 +149,12 @@ public: return byte_count; } + // Return the preferred proxy url + [[nodiscard]] virtual std::optional proxyUrl() const + { + return std::nullopt; + } + // Invoke the user-provided fetch callback virtual void run(FetchDoneFunc&& func, FetchResponse&& response) const {