diff --git a/src/daemon/daemon_config.cpp b/src/daemon/daemon_config.cpp index b643c6fabd..710a933b61 100644 --- a/src/daemon/daemon_config.cpp +++ b/src/daemon/daemon_config.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Canonical, Ltd. + * Copyright (C) 2017-2020 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,6 +31,8 @@ #include #include +#include +#include #include #include @@ -51,6 +53,39 @@ std::string server_name_from(const std::string& server_address) return "localhost"; return server_name; } + +std::unique_ptr discover_http_proxy() +{ + std::unique_ptr proxy_ptr{nullptr}; + + QString http_proxy{qgetenv("http_proxy")}; + if (http_proxy.isEmpty()) + { + // Some OS's are case senstive + http_proxy = qgetenv("HTTP_PROXY"); + } + + if (!http_proxy.isEmpty()) + { + if (!http_proxy.contains("://")) + { + http_proxy.prepend("http://"); + } + + QUrl proxy_url{http_proxy}; + const auto host = proxy_url.host(); + const auto port = proxy_url.port(); + + auto network_proxy = QNetworkProxy(QNetworkProxy::HttpProxy, host, static_cast(port), + proxy_url.userName(), proxy_url.password()); + + QNetworkProxy::setApplicationProxy(network_proxy); + + proxy_ptr = std::make_unique(network_proxy); + } + + return proxy_ptr; +} } // namespace mp::DaemonConfig::~DaemonConfig() @@ -116,9 +151,12 @@ std::unique_ptr mp::DaemonConfigBuilder::build() if (ssh_username.empty()) ssh_username = "ubuntu"; - return std::unique_ptr( - new DaemonConfig{std::move(url_downloader), std::move(factory), std::move(image_hosts), std::move(vault), - std::move(name_generator), std::move(ssh_key_provider), std::move(cert_provider), - std::move(client_cert_store), std::move(update_prompt), multiplexing_logger, cache_directory, - data_directory, server_address, ssh_username, connection_type, image_refresh_timer}); + if (network_proxy == nullptr) + network_proxy = discover_http_proxy(); + + return std::unique_ptr(new DaemonConfig{ + std::move(url_downloader), std::move(factory), std::move(image_hosts), std::move(vault), + std::move(name_generator), std::move(ssh_key_provider), std::move(cert_provider), std::move(client_cert_store), + std::move(update_prompt), multiplexing_logger, std::move(network_proxy), cache_directory, data_directory, + server_address, ssh_username, connection_type, image_refresh_timer}); } diff --git a/src/daemon/daemon_config.h b/src/daemon/daemon_config.h index 773167f0d4..920b6c7fe9 100644 --- a/src/daemon/daemon_config.h +++ b/src/daemon/daemon_config.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Canonical, Ltd. + * Copyright (C) 2017-2020 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,6 +34,8 @@ #include #include +#include + #include #include @@ -52,6 +54,7 @@ struct DaemonConfig const std::unique_ptr client_cert_store; const std::unique_ptr update_prompt; const std::shared_ptr logger; + const std::unique_ptr network_proxy; const multipass::Path cache_directory; const multipass::Path data_directory; const std::string server_address; @@ -72,6 +75,7 @@ struct DaemonConfigBuilder std::unique_ptr client_cert_store; std::unique_ptr update_prompt; std::unique_ptr logger; + std::unique_ptr network_proxy; multipass::Path cache_directory; multipass::Path data_directory; std::string server_address; diff --git a/src/network/url_downloader.cpp b/src/network/url_downloader.cpp index 24392225f8..d08535d5a5 100644 --- a/src/network/url_downloader.cpp +++ b/src/network/url_downloader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2019 Canonical, Ltd. + * Copyright (C) 2017-2020 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -99,6 +99,9 @@ QByteArray download(QNetworkAccessManager* manager, const Time& timeout, QUrl co const auto msg = reply->errorString().toStdString(); + if (reply->error() == QNetworkReply::ProxyAuthenticationRequiredError) + reply->abort(); + if (abort_download) throw mp::AbortedDownloadException{msg}; else diff --git a/tests/test_daemon.cpp b/tests/test_daemon.cpp index 0bfffba32e..7cd07d6029 100644 --- a/tests/test_daemon.cpp +++ b/tests/test_daemon.cpp @@ -30,6 +30,7 @@ #include #include +#include "mock_environment_helpers.h" #include "mock_virtual_machine_factory.h" #include "stub_cert_store.h" #include "stub_certprovider.h" @@ -46,8 +47,11 @@ #include #include +#include #include +#include + #include #include #include @@ -367,6 +371,28 @@ TEST_F(Daemon, failed_restart_command_returns_fulfilled_promise) EXPECT_TRUE(is_ready(status_promise.get_future())); } +TEST_F(Daemon, proxy_contains_valid_info) +{ + auto guard = sg::make_scope_guard([] { + // Resets proxy back to what the system is configured for + QNetworkProxyFactory::setUseSystemConfiguration(true); + }); + + QString username{"username"}; + QString password{"password"}; + QString hostname{"192.168.1.1"}; + qint16 port{3128}; + QString proxy = QString("%1:%2@%3:%4").arg(username).arg(password).arg(hostname).arg(port); + + mpt::SetEnvScope env("http_proxy", proxy.toUtf8()); + + auto config = config_builder.build(); + + EXPECT_THAT(config->network_proxy->user(), username); + EXPECT_THAT(config->network_proxy->password(), password); + EXPECT_THAT(config->network_proxy->hostName(), hostname); + EXPECT_THAT(config->network_proxy->port(), port); +} namespace {