From 7a3456c4da16ad8bcdc039f0b40a5a9653a1f103 Mon Sep 17 00:00:00 2001 From: Gregory Shklover Date: Mon, 14 Oct 2024 15:39:14 +0300 Subject: [PATCH 1/3] Added handling no_proxy override --- cpr/session.cpp | 9 +++++++++ test/proxy_tests.cpp | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/cpr/session.cpp b/cpr/session.cpp index b2263ec4b..5149238e5 100644 --- a/cpr/session.cpp +++ b/cpr/session.cpp @@ -180,6 +180,15 @@ void Session::prepareCommonShared() { curl_easy_setopt(curl_->handle, CURLOPT_PROXYPASSWORD, proxyAuth_.GetPassword(protocol)); } } + // handle NO_PROXY override passed through Proxies object + // Example: Proxies{"no_proxy": ""} will override environment variable definition with an empty list + const std::string no_proxy[] = {"no_proxy", "NO_PROXY"}; + for (const auto& item : no_proxy) { + if (proxies_.has(item)) { + curl_easy_setopt(curl_->handle, CURLOPT_NOPROXY, proxies_[item].c_str()); + break; + } + } #if LIBCURL_VERSION_NUM >= 0x071506 // 7.21.6 if (acceptEncoding_.empty()) { diff --git a/test/proxy_tests.cpp b/test/proxy_tests.cpp index ce5126dcb..35aa7523b 100644 --- a/test/proxy_tests.cpp +++ b/test/proxy_tests.cpp @@ -86,6 +86,25 @@ TEST(ProxyTests, ReferenceProxySessionTest) { EXPECT_EQ(ErrorCode::OK, response.error.code); } +if 0 +TEST(ProxyTests, NoProxyTest) { + std::putenv("NO_PROXY", "www.httpbin.org"); + Url url{"http://www.httpbin.org/get"}; + Proxies proxies{{"http", HTTP_PROXY, "no_proxy", ""}}; + Session session; + session.SetUrl(url); + session.SetProxies(proxies); + Response response = session.Get(); + EXPECT_EQ(url, response.url); + EXPECT_EQ(std::string{"application/json"}, response.header["content-type"]); + EXPECT_EQ(200, response.status_code); + EXPECT_EQ(ErrorCode::OK, response.error.code); + // TODO: check that access was performed through the proxy + // json body = json.parse(response.text); + // EXPECT_EQ(body["origin"], HTTP_PROXY.domain()); +} +#endif + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From 6c645c733e6e212eb55abb74686fbf116dc30c90 Mon Sep 17 00:00:00 2001 From: Gregory Shklover Date: Mon, 21 Oct 2024 13:15:11 +0300 Subject: [PATCH 2/3] Updated test --- cpr/session.cpp | 3 ++- test/proxy_tests.cpp | 52 ++++++++++++++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/cpr/session.cpp b/cpr/session.cpp index 5149238e5..13e287ad5 100644 --- a/cpr/session.cpp +++ b/cpr/session.cpp @@ -1,5 +1,6 @@ #include "cpr/session.h" +#include #include #include #include @@ -182,7 +183,7 @@ void Session::prepareCommonShared() { } // handle NO_PROXY override passed through Proxies object // Example: Proxies{"no_proxy": ""} will override environment variable definition with an empty list - const std::string no_proxy[] = {"no_proxy", "NO_PROXY"}; + const std::array no_proxy{"no_proxy", "NO_PROXY"}; for (const auto& item : no_proxy) { if (proxies_.has(item)) { curl_easy_setopt(curl_->handle, CURLOPT_NOPROXY, proxies_[item].c_str()); diff --git a/test/proxy_tests.cpp b/test/proxy_tests.cpp index 35aa7523b..0b5be2ff4 100644 --- a/test/proxy_tests.cpp +++ b/test/proxy_tests.cpp @@ -1,6 +1,8 @@ #include +#include #include +#include #include "cpr/cpr.h" @@ -86,24 +88,42 @@ TEST(ProxyTests, ReferenceProxySessionTest) { EXPECT_EQ(ErrorCode::OK, response.error.code); } -if 0 TEST(ProxyTests, NoProxyTest) { - std::putenv("NO_PROXY", "www.httpbin.org"); - Url url{"http://www.httpbin.org/get"}; - Proxies proxies{{"http", HTTP_PROXY, "no_proxy", ""}}; - Session session; - session.SetUrl(url); - session.SetProxies(proxies); - Response response = session.Get(); - EXPECT_EQ(url, response.url); - EXPECT_EQ(std::string{"application/json"}, response.header["content-type"]); - EXPECT_EQ(200, response.status_code); - EXPECT_EQ(ErrorCode::OK, response.error.code); - // TODO: check that access was performed through the proxy - // json body = json.parse(response.text); - // EXPECT_EQ(body["origin"], HTTP_PROXY.domain()); + setenv("NO_PROXY", "httpbin.org", 1); + try { + Url url{"http://www.httpbin.org/get"}; + Proxies proxies{{"http", HTTP_PROXY}, {"no_proxy", ""}}; + Session session; + session.SetUrl(url); + session.SetProxies(proxies); + Response response = session.Get(); + EXPECT_EQ(url, response.url); + EXPECT_EQ(std::string{"application/json"}, response.header["content-type"]); + EXPECT_EQ(200, response.status_code); + EXPECT_EQ(ErrorCode::OK, response.error.code); + + // check that access was performed through the proxy + std::string proxy_ip = HTTP_PROXY; + proxy_ip = proxy_ip.substr(0, proxy_ip.find(':')); + + // find "origin": "ip" in response: + bool found = false; + std::istringstream body(response.text); + std::string line; + while (std::getline(body, line)) { + // example: "origin": "123.456.789.123" + if (line.find("\"origin\":") != std::string::npos) { + found = line.find(proxy_ip) != std::string::npos; + break; + } + } + EXPECT_TRUE(found); + } catch (...) { + unsetenv("NO_PROXY"); + throw; + } + unsetenv("NO_PROXY"); } -#endif int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); From c8fb3e8535352ce818167abeae67a82663a8f6a0 Mon Sep 17 00:00:00 2001 From: Gregory Shklover Date: Tue, 22 Oct 2024 09:16:33 +0300 Subject: [PATCH 3/3] Updated no_proxy test --- test/proxy_tests.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/proxy_tests.cpp b/test/proxy_tests.cpp index 0b5be2ff4..a5a821c6f 100644 --- a/test/proxy_tests.cpp +++ b/test/proxy_tests.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -9,9 +10,14 @@ // TODO: This uses public servers for proxies and endpoints. This should be replaced with a source // code implementation inside server.cpp +// NOTES: +// * For no-proxy testing need to run the tests with direct connection to the internet +// * List of free proxies for testing can be found at https://proxy-list.org/english/index.php +// Example: #define HTTP_PROXY "http://162.223.90.130:80" #define HTTP_PROXY "51.159.4.98:80" #define HTTPS_PROXY "51.104.53.182:8000" + using namespace cpr; TEST(ProxyTests, SingleProxyTest) { @@ -81,6 +87,7 @@ TEST(ProxyTests, ReferenceProxySessionTest) { Session session; session.SetUrl(url); session.SetProxies(proxies); + session.SetTimeout(std::chrono::seconds(10)); Response response = session.Get(); EXPECT_EQ(url, response.url); EXPECT_EQ(std::string{"application/json"}, response.header["content-type"]); @@ -96,6 +103,7 @@ TEST(ProxyTests, NoProxyTest) { Session session; session.SetUrl(url); session.SetProxies(proxies); + session.SetTimeout(std::chrono::seconds(10)); Response response = session.Get(); EXPECT_EQ(url, response.url); EXPECT_EQ(std::string{"application/json"}, response.header["content-type"]); @@ -104,6 +112,11 @@ TEST(ProxyTests, NoProxyTest) { // check that access was performed through the proxy std::string proxy_ip = HTTP_PROXY; + if (proxy_ip[0] == 'h') { + // drop protocol: + proxy_ip = proxy_ip.substr(proxy_ip.find(':') + 3); + } + // drop port: proxy_ip = proxy_ip.substr(0, proxy_ip.find(':')); // find "origin": "ip" in response: