diff --git a/include/motis/config.h b/include/motis/config.h index df12b2709..97ac5e2d2 100644 --- a/include/motis/config.h +++ b/include/motis/config.h @@ -115,6 +115,7 @@ struct config { unsigned update_interval_{60}; unsigned http_timeout_{10}; unsigned cache_size_{50}; + std::optional proxy_; }; std::optional gbfs_{}; diff --git a/include/motis/http_client.h b/include/motis/http_client.h index 78f59e9ce..1a413b89e 100644 --- a/include/motis/http_client.h +++ b/include/motis/http_client.h @@ -38,6 +38,14 @@ struct http_client { bool ssl_{}; }; + struct proxy_settings { + operator bool() const { return !host_.empty(); } + + std::string host_; + std::string port_; + bool ssl_{}; + }; + struct connection; struct request; @@ -46,8 +54,12 @@ struct http_client { boost::asio::awaitable get( boost::urls::url url, std::map headers); + void set_proxy(boost::urls::url const&); + hash_map> connections_; std::chrono::seconds timeout_{std::chrono::seconds{10}}; + + proxy_settings proxy_{}; }; } // namespace motis diff --git a/src/gbfs/update.cc b/src/gbfs/update.cc index 8e958a69a..d62441f31 100644 --- a/src/gbfs/update.cc +++ b/src/gbfs/update.cc @@ -140,6 +140,9 @@ struct gbfs_update { gbfs_data const* prev_d) : c_{c}, w_{w}, l_{l}, d_{d}, prev_d_{prev_d} { client_.timeout_ = std::chrono::seconds{c.http_timeout_}; + if (c.proxy_ && !c.proxy_->empty()) { + client_.set_proxy(boost::urls::url{*c.proxy_}); + } } awaitable run() { diff --git a/src/http_client.cc b/src/http_client.cc index 029a415b8..2eb259c09 100644 --- a/src/http_client.cc +++ b/src/http_client.cc @@ -88,6 +88,7 @@ struct http_client::connection connection(Executor const& executor, connection_key key, std::chrono::seconds const timeout, + proxy_settings const& proxy, std::size_t const max_in_flight = 1) : key_{std::move(key)}, unlimited_pipelining_{max_in_flight == kUnlimitedHttpPipelining}, @@ -95,7 +96,8 @@ struct http_client::connection requests_in_flight_{std::make_unique< asio::experimental::channel>( executor, max_in_flight)}, - timeout_{timeout} { + timeout_{timeout}, + proxy_{proxy} { ssl_ctx_.set_default_verify_paths(); ssl_ctx_.set_verify_mode(ssl::verify_none); ssl_ctx_.set_options(ssl::context::default_workarounds | @@ -128,15 +130,17 @@ struct http_client::connection auto executor = co_await asio::this_coro::executor; auto resolver = asio::ip::tcp::resolver{executor}; - auto const results = - co_await resolver.async_resolve(key_.host_, key_.port_); + auto const host = proxy_ ? proxy_.host_ : key_.host_; + auto const port = proxy_ ? proxy_.port_ : key_.port_; + + auto const results = co_await resolver.async_resolve(host, port); ++n_connects_; if (ssl()) { ssl_stream_ = std::make_unique>(executor, ssl_ctx_); if (!SSL_set_tlsext_host_name(ssl_stream_->native_handle(), - const_cast(key_.host_.c_str()))) { + const_cast(host.c_str()))) { throw boost::system::system_error{{static_cast(::ERR_get_error()), asio::error::get_ssl_category()}}; } @@ -290,7 +294,7 @@ struct http_client::connection } while (!pending_requests_.empty()); } - bool ssl() const { return key_.ssl_; } + bool ssl() const { return proxy_ ? proxy_.ssl_ : key_.ssl_; } connection_key key_{}; bool unlimited_pipelining_{false}; @@ -313,6 +317,7 @@ struct http_client::connection ssl::context ssl_ctx_{ssl::context::tlsv12_client}; std::chrono::seconds timeout_; + http_client::proxy_settings proxy_; unsigned n_sent_{}; unsigned n_received_{}; @@ -335,7 +340,8 @@ asio::awaitable http_client::get( auto executor = co_await asio::this_coro::executor; if (auto const it = connections_.find(key); it == connections_.end()) { - auto conn = std::make_shared(executor, key, timeout_, 1); + auto conn = + std::make_shared(executor, key, timeout_, proxy_, 1); connections_[key] = conn; asio::co_spawn(executor, conn->run(), asio::detached); } @@ -348,4 +354,10 @@ asio::awaitable http_client::get( co_return response; } +void http_client::set_proxy(boost::urls::url const& url) { + proxy_.ssl_ = url.scheme_id() == boost::urls::scheme::https; + proxy_.host_ = url.host(); + proxy_.port_ = url.has_port() ? url.port() : (proxy_.ssl_ ? "443" : "80"); +} + } // namespace motis