WIP: proxy_support #3
4 changed files with 53 additions and 54 deletions
|
@ -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
|
# 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
|
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
|
||||||
|
|
||||||
if [[ $SHELLCHECK_RES != 0 ]]; then
|
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"
|
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)"
|
cmake --build ${GTEST_FOLDER} --target larra_xmpp_tests --parallel "$(nproc)"
|
||||||
|
|
||||||
printf "\n\tLaunch GTests to check\n"
|
printf "\n\tLaunch GTests to check\n"
|
||||||
# ./larra_xmpp_tests --gtest_brief=1
|
./larra_xmpp_tests --gtest_brief=1
|
||||||
|
|
||||||
GTEST_RES=$?
|
GTEST_RES=$?
|
||||||
cd ${PROJECT_FOLDER} && rm -rf ${GTEST_FOLDER?}
|
cd ${PROJECT_FOLDER} && rm -rf ${GTEST_FOLDER?}
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -40,7 +40,6 @@ temp*
|
||||||
#/.idea/codeStyles/Project.xml
|
#/.idea/codeStyles/Project.xml
|
||||||
#/.idea/vcs.xml
|
#/.idea/vcs.xml
|
||||||
/.idea/
|
/.idea/
|
||||||
.githooks/
|
|
||||||
|
|
||||||
sha512sum marked this conversation as resolved
|
|||||||
|
|
||||||
|
|
||||||
|
|
|
@ -171,25 +171,25 @@ auto ConnectViaProxy(Socket& socket, const HttpProxy& param_proxy, std::string_v
|
||||||
|
|
||||||
// ответ от прокси-сервера
|
// ответ от прокси-сервера
|
||||||
boost::asio::streambuf response;
|
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);
|
||||||
|
|
||||||
// статус ответа
|
// статус ответа
|
||||||
sha512sum
commented
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::istream responseStream(&response);
|
||||||
std::string http_version;
|
std::string httpVersion;
|
||||||
unsigned int status_code = 0;
|
unsigned int statusCode = 0;
|
||||||
std::string status_message;
|
std::string statusMessage;
|
||||||
|
|
||||||
response_stream >> http_version >> status_code;
|
responseStream >> httpVersion >> statusCode;
|
||||||
std::getline(response_stream, status_message);
|
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");
|
throw std::runtime_error("Invalid HTTP response from proxy");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(status_code != kSuccessStatusCode) {
|
if(statusCode != kSuccessStatusCode) {
|
||||||
std::ostringstream error_stream;
|
std::ostringstream errorStream;
|
||||||
error_stream << http_version << " " << status_code << " " << status_message;
|
errorStream << httpVersion << " " << statusCode << " " << statusMessage;
|
||||||
throw std::runtime_error("HTTP proxy CONNECT failed: " + error_stream.str());
|
throw std::runtime_error("HTTP proxy CONNECT failed: " + errorStream.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
co_return;
|
co_return;
|
||||||
|
|
|
@ -18,36 +18,36 @@ class ProxyTest : public ::testing::Test {
|
||||||
TEST_F(ProxyTest, ConnectViaHttpProxy_SuccessfulResponse) {
|
TEST_F(ProxyTest, ConnectViaHttpProxy_SuccessfulResponse) {
|
||||||
HttpProxy proxy{"proxy_host", 8080};
|
HttpProxy proxy{"proxy_host", 8080};
|
||||||
|
|
||||||
std::string target_host = "target_host";
|
std::string targetHost = "target_host";
|
||||||
uint16_t target_port = 80;
|
uint16_t targetPort = 80;
|
||||||
|
|
||||||
std::string expected_request =
|
std::string expectedRequest =
|
||||||
std::format("CONNECT {}:{} HTTP/1.1\r\nHost: {}:{}\r\n\r\n", target_host, target_port, target_host, target_port);
|
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;
|
||||||
|
|
||||||
asio::co_spawn(
|
asio::co_spawn(
|
||||||
io_context,
|
io_context,
|
||||||
[&]() -> asio::awaitable<void> {
|
[&]() -> asio::awaitable<void> {
|
||||||
try {
|
try {
|
||||||
co_await client::impl::ConnectViaProxy(mock_socket, proxy, target_host, target_port);
|
co_await client::impl::ConnectViaProxy(mock_socket, proxy, targetHost, targetPort);
|
||||||
connect_successful = true;
|
connectSuccessful = true;
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
connect_successful = false;
|
connectSuccessful = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
asio::detached);
|
asio::detached);
|
||||||
|
|
||||||
io_context.run();
|
io_context.run();
|
||||||
|
|
||||||
std::string sent_data = mock_socket.GetSentData();
|
std::string sentData = mock_socket.GetSentData();
|
||||||
|
|
||||||
EXPECT_EQ(sent_data, expected_request);
|
EXPECT_EQ(sentData, expectedRequest);
|
||||||
EXPECT_TRUE(connect_successful);
|
EXPECT_TRUE(connectSuccessful);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 2: Connect via SOCKS proxy
|
// Test 2: Connect via SOCKS proxy
|
||||||
|
@ -58,53 +58,53 @@ TEST(Socks5ProxyTest, ConnectViaProxy) {
|
||||||
larra::xmpp::impl::MockSocket socket{executor};
|
larra::xmpp::impl::MockSocket socket{executor};
|
||||||
|
|
||||||
// expected server responses
|
// expected server responses
|
||||||
std::string server_response;
|
std::string serverResponse;
|
||||||
server_response += "\x05\x00"; // VER, METHOD
|
serverResponse += "\x05\x00"; // VER, METHOD
|
||||||
server_response += "\x05\x00\x00\x01"; // VER, REP, RSV, ATYP (IPv4)
|
serverResponse += "\x05\x00\x00\x01"; // VER, REP, RSV, ATYP (IPv4)
|
||||||
server_response += "\x7F\x00\x00\x01"; // BND.ADDR (127.0.0.1)
|
serverResponse += "\x7F\x00\x00\x01"; // BND.ADDR (127.0.0.1)
|
||||||
server_response += "\x1F\x90"; // BND.PORT (8080)
|
serverResponse += "\x1F\x90"; // BND.PORT (8080)
|
||||||
|
|
||||||
socket.AddReceivedData(server_response);
|
socket.AddReceivedData(serverResponse);
|
||||||
|
|
||||||
Socks5Proxy proxy{"proxy.example.com", 1080};
|
Socks5Proxy proxy{"proxy.example.com", 1080};
|
||||||
std::string target_hostname = "target.example.com";
|
std::string targetHostname = "target.example.com";
|
||||||
std::uint16_t target_port = 80;
|
std::uint16_t targetPort = 80;
|
||||||
|
|
||||||
boost::asio::co_spawn(
|
boost::asio::co_spawn(
|
||||||
executor,
|
executor,
|
||||||
[&]() -> boost::asio::awaitable<void> {
|
[&]() -> 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
|
// Expected client greeting
|
||||||
std::string expected_greeting = "\x05\x01\x00";
|
std::string expectedGreeting = "\x05\x01\x00";
|
||||||
|
|
||||||
// Expected CONNECT request
|
// Expected CONNECT request
|
||||||
std::array<std::uint8_t, 262> expected_request{};
|
std::array<std::uint8_t, 262> expectedRequest{};
|
||||||
std::size_t req_len = 0;
|
std::size_t req_len = 0;
|
||||||
|
|
||||||
expected_request[req_len++] = 0x05; // VER
|
expectedRequest[req_len++] = 0x05; // VER
|
||||||
expected_request[req_len++] = 0x01; // CMD: CONNECT
|
expectedRequest[req_len++] = 0x01; // CMD: CONNECT
|
||||||
expected_request[req_len++] = 0x00; // RSV
|
expectedRequest[req_len++] = 0x00; // RSV
|
||||||
expected_request[req_len++] = 0x03; // ATYP: DOMAINNAME
|
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());
|
std::memcpy(&expectedRequest[req_len], targetHostname.data(), targetHostname.size());
|
||||||
req_len += target_hostname.size();
|
req_len += targetHostname.size();
|
||||||
|
|
||||||
std::uint16_t network_order_port = htons(target_port);
|
std::uint16_t networkOrderPort = htons(targetPort);
|
||||||
expected_request[req_len++] = static_cast<std::uint8_t>((network_order_port >> 8) & 0xFF);
|
expectedRequest[req_len++] = static_cast<std::uint8_t>((networkOrderPort >> 8) & 0xFF);
|
||||||
expected_request[req_len++] = static_cast<std::uint8_t>(network_order_port & 0xFF);
|
expectedRequest[req_len++] = static_cast<std::uint8_t>(networkOrderPort & 0xFF);
|
||||||
|
|
||||||
std::string expected_data = expected_greeting;
|
std::string expectedData = expectedGreeting;
|
||||||
auto transformed_view = expected_request | std::views::take(req_len) | std::views::transform([](std::uint8_t byte) {
|
auto transformed_view = expectedRequest | std::views::take(req_len) | std::views::transform([](std::uint8_t byte) {
|
||||||
return static_cast<char>(byte);
|
return static_cast<char>(byte);
|
||||||
});
|
});
|
||||||
|
|
||||||
expected_data.append(std::ranges::to<std::string>(transformed_view));
|
expectedData.append(std::ranges::to<std::string>(transformed_view));
|
||||||
EXPECT_EQ(sent_data, expected_data);
|
EXPECT_EQ(sentData, expectedData);
|
||||||
|
|
||||||
co_return;
|
co_return;
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue
Why .githooks ???