Skip to content

Commit

Permalink
Merge pull request #1125 from gregory-shklover/gshklove_noproxy
Browse files Browse the repository at this point in the history
Added handling no_proxy override through Proxies
  • Loading branch information
COM8 authored Dec 22, 2024
2 parents c44f8d5 + c8fb3e8 commit 0e6bf15
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 0 deletions.
10 changes: 10 additions & 0 deletions cpr/session.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "cpr/session.h"

#include <array>
#include <atomic>
#include <cassert>
#include <cstdint>
Expand Down Expand Up @@ -180,6 +181,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::array<std::string, 2> 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()) {
Expand Down
52 changes: 52 additions & 0 deletions test/proxy_tests.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
#include <gtest/gtest.h>

#include <chrono>
#include <stdlib.h>
#include <string>
#include <sstream>

#include "cpr/cpr.h"

// 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) {
Expand Down Expand Up @@ -79,13 +87,57 @@ 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"]);
EXPECT_EQ(200, response.status_code);
EXPECT_EQ(ErrorCode::OK, response.error.code);
}

TEST(ProxyTests, NoProxyTest) {
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);
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"]);
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;
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:
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");
}

int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
Expand Down

0 comments on commit 0e6bf15

Please sign in to comment.