WIP: proxy_support #3

Draft
sectapunterx wants to merge 6 commits from proxy_support into main
4 changed files with 53 additions and 54 deletions
Showing only changes of commit 760bc2ab68 - Show all commits

View file

@ -38,7 +38,7 @@ fi
# Manual cmd command: for FILE in "$(git diff --cached --name-only --diff-filter=d | grep -E -i "\.(sh)$") .githooks/pre-commit"; do shellcheck -S warning $FILE; done
#
SHELLCHECK_RES=0
# for FILE in $GIT_SCRIPT_FILES; do shellcheck -S warning $FILE; RET_CODE=$?; SHELLCHECK_RES=$(( RET_CODE + SHELLCHECK_RES )); done
for FILE in $GIT_SCRIPT_FILES; do shellcheck -S warning $FILE; RET_CODE=$?; SHELLCHECK_RES=$(( RET_CODE + SHELLCHECK_RES )); done
sha512sum marked this conversation as resolved Outdated

??????

??????
if [[ $SHELLCHECK_RES != 0 ]]; then
printf "\n\t ${RED}[ERROR] shell scripts check FAILED!${NC} Fix above errors before commiting your changes. (check .githooks/pre-commit for additional info)\n"
@ -62,7 +62,7 @@ printf "\n\tBuild GTests to check (takes up to 30 seconds)"
cmake --build ${GTEST_FOLDER} --target larra_xmpp_tests --parallel "$(nproc)"
printf "\n\tLaunch GTests to check\n"
# ./larra_xmpp_tests --gtest_brief=1
./larra_xmpp_tests --gtest_brief=1
sha512sum marked this conversation as resolved Outdated

?????

?????
GTEST_RES=$?
cd ${PROJECT_FOLDER} && rm -rf ${GTEST_FOLDER?}

1
.gitignore vendored
View file

@ -40,7 +40,6 @@ temp*
#/.idea/codeStyles/Project.xml
#/.idea/vcs.xml
/.idea/
.githooks/
sha512sum marked this conversation as resolved
Review

Why .githooks ???

Why .githooks ???

View file

@ -171,25 +171,25 @@ auto ConnectViaProxy(Socket& socket, const HttpProxy& param_proxy, std::string_v
// ответ от прокси-сервера
boost::asio::streambuf response;
std::size_t bytes_transferred = co_await boost::asio::async_read_until(socket, response, kEndOfHeaders, boost::asio::use_awaitable);
std::size_t bytesTransferred = co_await boost::asio::async_read_until(socket, response, kEndOfHeaders, boost::asio::use_awaitable);

Code style. Use camelCase

Code style. Use camelCase
// статус ответа
Review

Meaningless comments, variable names reflect what they contain. No need to duplicate. And use English for comments in code

Meaningless comments, variable names reflect what they contain. No need to duplicate. And use English for comments in code
std::istream response_stream(&response);
std::string http_version;
unsigned int status_code = 0;
std::string status_message;
std::istream responseStream(&response);
std::string httpVersion;

camelCase

camelCase
unsigned int statusCode = 0;
std::string statusMessage;
response_stream >> http_version >> status_code;
std::getline(response_stream, status_message);
responseStream >> httpVersion >> statusCode;
std::getline(responseStream, statusMessage);
if(!response_stream || http_version.substr(0, kEndOfHttpSubstring) != "HTTP/") {
if(!responseStream || httpVersion.substr(0, kEndOfHttpSubstring) != "HTTP/") {
throw std::runtime_error("Invalid HTTP response from proxy");
}
if(status_code != kSuccessStatusCode) {
std::ostringstream error_stream;
error_stream << http_version << " " << status_code << " " << status_message;
throw std::runtime_error("HTTP proxy CONNECT failed: " + error_stream.str());
if(statusCode != kSuccessStatusCode) {
std::ostringstream errorStream;
errorStream << httpVersion << " " << statusCode << " " << statusMessage;
throw std::runtime_error("HTTP proxy CONNECT failed: " + errorStream.str());
}
co_return;

View file

@ -18,36 +18,36 @@ class ProxyTest : public ::testing::Test {
TEST_F(ProxyTest, ConnectViaHttpProxy_SuccessfulResponse) {
HttpProxy proxy{"proxy_host", 8080};
std::string target_host = "target_host";
uint16_t target_port = 80;
std::string targetHost = "target_host";
uint16_t targetPort = 80;
std::string expected_request =
std::format("CONNECT {}:{} HTTP/1.1\r\nHost: {}:{}\r\n\r\n", target_host, target_port, target_host, target_port);
std::string expectedRequest =
std::format("CONNECT {}:{} HTTP/1.1\r\nHost: {}:{}\r\n\r\n", targetHost, targetPort, targetHost, targetPort);
std::string proxy_response = "HTTP/1.1 200 Connection established\r\n\r\n";
std::string proxyResponse = "HTTP/1.1 200 Connection established\r\n\r\n";
mock_socket.AddReceivedData(proxy_response);
mock_socket.AddReceivedData(proxyResponse);
bool connect_successful = false;
bool connectSuccessful = false;

camelCase

camelCase
asio::co_spawn(
io_context,
[&]() -> asio::awaitable<void> {
try {
co_await client::impl::ConnectViaProxy(mock_socket, proxy, target_host, target_port);
connect_successful = true;
co_await client::impl::ConnectViaProxy(mock_socket, proxy, targetHost, targetPort);
connectSuccessful = true;
} catch(...) {
connect_successful = false;
connectSuccessful = false;
}
},
asio::detached);
io_context.run();
std::string sent_data = mock_socket.GetSentData();
std::string sentData = mock_socket.GetSentData();
EXPECT_EQ(sent_data, expected_request);
EXPECT_TRUE(connect_successful);
EXPECT_EQ(sentData, expectedRequest);
EXPECT_TRUE(connectSuccessful);
}
// Test 2: Connect via SOCKS proxy
@ -58,53 +58,53 @@ TEST(Socks5ProxyTest, ConnectViaProxy) {
larra::xmpp::impl::MockSocket socket{executor};
// expected server responses
std::string server_response;
server_response += "\x05\x00"; // VER, METHOD
server_response += "\x05\x00\x00\x01"; // VER, REP, RSV, ATYP (IPv4)
server_response += "\x7F\x00\x00\x01"; // BND.ADDR (127.0.0.1)
server_response += "\x1F\x90"; // BND.PORT (8080)
std::string serverResponse;

camelCase

camelCase
serverResponse += "\x05\x00"; // VER, METHOD
serverResponse += "\x05\x00\x00\x01"; // VER, REP, RSV, ATYP (IPv4)
serverResponse += "\x7F\x00\x00\x01"; // BND.ADDR (127.0.0.1)
serverResponse += "\x1F\x90"; // BND.PORT (8080)
socket.AddReceivedData(server_response);
socket.AddReceivedData(serverResponse);
Socks5Proxy proxy{"proxy.example.com", 1080};
std::string target_hostname = "target.example.com";
std::uint16_t target_port = 80;
std::string targetHostname = "target.example.com";
std::uint16_t targetPort = 80;
boost::asio::co_spawn(
executor,
[&]() -> boost::asio::awaitable<void> {
co_await client::impl::ConnectViaProxy(socket, proxy, target_hostname, target_port);
co_await client::impl::ConnectViaProxy(socket, proxy, targetHostname, targetPort);
auto sent_data = socket.GetSentData();
auto sentData = socket.GetSentData();
// Expected client greeting
std::string expected_greeting = "\x05\x01\x00";
std::string expectedGreeting = "\x05\x01\x00";
// Expected CONNECT request
std::array<std::uint8_t, 262> expected_request{};
std::array<std::uint8_t, 262> expectedRequest{};
std::size_t req_len = 0;
expected_request[req_len++] = 0x05; // VER
expected_request[req_len++] = 0x01; // CMD: CONNECT
expected_request[req_len++] = 0x00; // RSV
expected_request[req_len++] = 0x03; // ATYP: DOMAINNAME
expectedRequest[req_len++] = 0x05; // VER
expectedRequest[req_len++] = 0x01; // CMD: CONNECT
expectedRequest[req_len++] = 0x00; // RSV
expectedRequest[req_len++] = 0x03; // ATYP: DOMAINNAME
expected_request[req_len++] = static_cast<std::uint8_t>(target_hostname.size()); // domain length
expectedRequest[req_len++] = static_cast<std::uint8_t>(targetHostname.size()); // domain length
std::memcpy(&expected_request[req_len], target_hostname.data(), target_hostname.size());
req_len += target_hostname.size();
std::memcpy(&expectedRequest[req_len], targetHostname.data(), targetHostname.size());
req_len += targetHostname.size();
std::uint16_t network_order_port = htons(target_port);
expected_request[req_len++] = static_cast<std::uint8_t>((network_order_port >> 8) & 0xFF);
expected_request[req_len++] = static_cast<std::uint8_t>(network_order_port & 0xFF);
std::uint16_t networkOrderPort = htons(targetPort);
expectedRequest[req_len++] = static_cast<std::uint8_t>((networkOrderPort >> 8) & 0xFF);
expectedRequest[req_len++] = static_cast<std::uint8_t>(networkOrderPort & 0xFF);
std::string expected_data = expected_greeting;
auto transformed_view = expected_request | std::views::take(req_len) | std::views::transform([](std::uint8_t byte) {
std::string expectedData = expectedGreeting;
auto transformed_view = expectedRequest | std::views::take(req_len) | std::views::transform([](std::uint8_t byte) {
return static_cast<char>(byte);
});
expected_data.append(std::ranges::to<std::string>(transformed_view));
EXPECT_EQ(sent_data, expected_data);
expectedData.append(std::ranges::to<std::string>(transformed_view));
EXPECT_EQ(sentData, expectedData);
co_return;
},