From 9236827ba538a60a3fe82c412ba93bca63ac0f30 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 8 Jan 2026 08:12:26 -0600 Subject: [PATCH] refactor: use symbolic names for server relative paths (#8080) * refactor: use TrHttpServerDefaultBasePath in remote.cc refactor: use TrHttpServerRpcRelativePath in remote.cc * refactor: use TrHttpServerDefaultBasePath in rpc-server.cc refactor: use TrHttpServerRpcRelativePath in rpc-server.cc * refactor: remove unused TR_DEFAULT_RPC_URL_STR --- libtransmission/rpc-server.cc | 43 ++++++++++++++++++++-------------- libtransmission/rpc-server.h | 2 +- libtransmission/transmission.h | 3 +-- utils/remote.cc | 19 ++++----------- 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/libtransmission/rpc-server.cc b/libtransmission/rpc-server.cc index 92b6f392f..63d114af7 100644 --- a/libtransmission/rpc-server.cc +++ b/libtransmission/rpc-server.cc @@ -315,12 +315,17 @@ void handle_web_client(struct evhttp_request* req, tr_rpc_server const* server) return; } - // convert the URL path component (ex: "/transmission/web/images/favicon.png") - // into a filesystem path (ex: "/usr/share/transmission/web/images/favicon.png") + // convert the URL path component into a filesystem path, e.g. + // "/transmission/web/images/favicon.png" -> + // "/usr/share/transmission/web/images/favicon.png") + auto subpath = std::string_view{ evhttp_request_get_uri(req) }; - // remove the "/transmission/web/" prefix - static auto constexpr Web = "web/"sv; - auto subpath = std::string_view{ evhttp_request_get_uri(req) }.substr(std::size(server->url()) + std::size(Web)); + // remove the web base path eg "/transmission/web/" + { + auto const& base_path = server->url(); + static auto constexpr Web = TrHttpServerWebRelativePath; + subpath = subpath.substr(std::size(base_path) + std::size(Web)); + } // remove any trailing query / fragment subpath = subpath.substr(0, subpath.find_first_of("?#"sv)); @@ -580,17 +585,20 @@ void handle_request(struct evhttp_request* req, void* arg) server->login_attempts_ = 0; - auto const* const uri = evhttp_request_get_uri(req); - auto const uri_sv = std::string_view{ uri }; - auto const location = tr_strv_starts_with(uri_sv, server->url()) ? uri_sv.substr(std::size(server->url())) : ""sv; + // eg '/transmission/web/' and '/transmission/rpc' + auto const& base_path = server->url(); + auto const web_base_path = tr_urlbuf{ base_path, TrHttpServerWebRelativePath }; + auto const rpc_base_path = tr_urlbuf{ base_path, TrHttpServerRpcRelativePath }; + auto const deprecated_web_path = tr_urlbuf{ base_path, "web" /*no trailing slash*/ }; - if (std::empty(location) || location == "web"sv) + char const* const uri = evhttp_request_get_uri(req); + + if (!tr_strv_starts_with(uri, base_path) || uri == deprecated_web_path) { - auto const new_location = fmt::format("{:s}web/", server->url()); - evhttp_add_header(output_headers, "Location", new_location.c_str()); + evhttp_add_header(output_headers, "Location", web_base_path.c_str()); send_simple_response(req, HTTP_MOVEPERM, nullptr); } - else if (tr_strv_starts_with(location, "web/"sv)) + else if (tr_strv_starts_with(uri, web_base_path)) { handle_web_client(req, server); } @@ -638,7 +646,7 @@ void handle_request(struct evhttp_request* req, void* arg) send_simple_response(req, 409, body.c_str()); } #endif - else if (tr_strv_starts_with(location, "rpc"sv)) + else if (tr_strv_starts_with(uri, rpc_base_path)) { handle_rpc(req, server); } @@ -648,7 +656,7 @@ void handle_request(struct evhttp_request* req, void* arg) fmt::format( fmt::runtime(_("Unknown URI from {host}: '{uri}'")), fmt::arg("host", remote_host), - fmt::arg("uri", uri_sv))); + fmt::arg("uri", uri))); send_simple_response(req, HTTP_NOTFOUND, uri); } } @@ -983,9 +991,9 @@ void tr_rpc_server::load(Settings&& settings) { settings_ = std::move(settings); - if (!tr_strv_ends_with(settings_.url, '/')) + if (std::string& path = settings_.url; !tr_strv_ends_with(path, '/')) { - settings_.url = fmt::format("{:s}/", settings_.url); + path = fmt::format("{:s}/", path); } host_whitelist_ = parse_whitelist(settings_.host_whitelist_str); @@ -1012,7 +1020,8 @@ void tr_rpc_server::load(Settings&& settings) } if (this->is_enabled()) { - auto const rpc_uri = bind_address_->to_string(port()) + settings_.url; + auto const& base_path = url(); + auto const rpc_uri = bind_address_->to_string(port()) + base_path; tr_logAddInfo(fmt::format(fmt::runtime(_("Serving RPC and Web requests on {address}")), fmt::arg("address", rpc_uri))); session->run_in_session_thread(start_server, this); diff --git a/libtransmission/rpc-server.h b/libtransmission/rpc-server.h index 661413124..88df76444 100644 --- a/libtransmission/rpc-server.h +++ b/libtransmission/rpc-server.h @@ -67,7 +67,7 @@ public: std::string bind_address_str = "0.0.0.0"; std::string host_whitelist_str; std::string salted_password; - std::string url = TR_DEFAULT_RPC_URL_STR; + std::string url = std::string{ TrHttpServerDefaultBasePath }; std::string username; std::string whitelist_str = TR_DEFAULT_RPC_WHITELIST; tr_mode_t socket_mode = 0750; diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index 8b2fefc50..550522887 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -136,7 +136,6 @@ size_t tr_getDefaultDownloadDirToBuf(char* buf, size_t buflen); #define TR_DEFAULT_RPC_WHITELIST "127.0.0.1,::1" #define TR_DEFAULT_RPC_PORT_STR "9091" inline auto constexpr TrDefaultRpcPort = 9091U; -#define TR_DEFAULT_RPC_URL_STR "/transmission/" #define TR_DEFAULT_PEER_PORT_STR "51413" inline auto constexpr TrDefaultPeerPort = 51413U; #define TR_DEFAULT_PEER_SOCKET_TOS_STR "le" @@ -145,7 +144,7 @@ inline auto constexpr TrDefaultPeerLimitGlobal = 200U; #define TR_DEFAULT_PEER_LIMIT_TORRENT_STR "50" inline auto constexpr TrDefaultPeerLimitTorrent = 50U; -inline auto constexpr TrHttpServerDefaultBasePath = std::string_view{ TR_DEFAULT_RPC_URL_STR }; +inline auto constexpr TrHttpServerDefaultBasePath = std::string_view{ "/transmission/" }; inline auto constexpr TrHttpServerRpcRelativePath = std::string_view{ "rpc" }; inline auto constexpr TrHttpServerWebRelativePath = std::string_view{ "web/" }; diff --git a/utils/remote.cc b/utils/remote.cc index 592469466..06dd70b67 100644 --- a/utils/remote.cc +++ b/utils/remote.cc @@ -50,10 +50,6 @@ using namespace libtransmission::Values; namespace { -auto constexpr DefaultPort = uint16_t{ TrDefaultRpcPort }; -char constexpr DefaultHost[] = "localhost"; -char constexpr DefaultUrl[] = TR_DEFAULT_RPC_URL_STR "rpc/"; - char constexpr MyName[] = "transmission-remote"; char constexpr Usage[] = "transmission-remote " LONG_VERSION_STRING "\n" @@ -3522,12 +3518,12 @@ void get_host_and_port_and_rpc_url( auto const sv = std::string_view{ argv[1] }; if (tr_strv_starts_with(sv, "http://")) /* user passed in http rpc url */ { - rpcurl = fmt::format("{:s}/rpc/", sv.substr(7)); + rpcurl = fmt::format("{:s}/{:s}", sv.substr(7), TrHttpServerRpcRelativePath); } else if (tr_strv_starts_with(sv, "https://")) /* user passed in https rpc url */ { config.use_ssl = true; - rpcurl = fmt::format("{:s}/rpc/", sv.substr(8)); + rpcurl = fmt::format("{:s}/{:s}", sv.substr(8), TrHttpServerRpcRelativePath); } else if (parse_port_string(sv, port)) { @@ -3568,8 +3564,8 @@ int tr_main(int argc, char* argv[]) tr_locale_set_global(""); auto config = RemoteConfig{}; - auto port = DefaultPort; - auto host = std::string{}; + auto port = uint16_t{ TrDefaultRpcPort }; + auto host = std::string{ "localhost" }; auto rpcurl = std::string{}; if (argc < 2) @@ -3580,14 +3576,9 @@ int tr_main(int argc, char* argv[]) get_host_and_port_and_rpc_url(argc, argv, host, port, rpcurl, config); - if (std::empty(host)) - { - host = DefaultHost; - } - if (std::empty(rpcurl)) { - rpcurl = fmt::format("{:s}:{:d}{:s}", host, port, DefaultUrl); + rpcurl = fmt::format("{:s}:{:d}{:s}{:s}", host, port, TrHttpServerDefaultBasePath, TrHttpServerRpcRelativePath); } return process_args(rpcurl.c_str(), argc, (char const* const*)argv, config);