#include #include #include #include using namespace larra::xmpp; using boost::asio::ip::tcp; namespace asio = boost::asio; class ProxyTest : public ::testing::Test { protected: boost::asio::io_context io_context; larra::xmpp::impl::MockSocket mock_socket{io_context.get_executor()}; }; // Test 1: Connect via HTTP proxy with successful server response TEST_F(ProxyTest, ConnectViaHttpProxy_SuccessfulResponse) { HttpProxy proxy{"proxy_host", 8080}; std::string target_host = "target_host"; uint16_t target_port = 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 proxy_response = "HTTP/1.1 200 Connection established\r\n\r\n"; mock_socket.AddReceivedData(proxy_response); bool connect_successful = false; asio::co_spawn( io_context, [&]() -> asio::awaitable { try { co_await client::impl::ConnectViaProxy(mock_socket, proxy, target_host, target_port); connect_successful = true; } catch(...) { connect_successful = false; } }, asio::detached); io_context.run(); std::string sent_data = mock_socket.GetSentData(); EXPECT_EQ(sent_data, expected_request); EXPECT_TRUE(connect_successful); } // Test 2: Connect via SOCKS proxy TEST(Socks5ProxyTest, ConnectViaProxy) { boost::asio::io_context io; auto executor = io.get_executor(); 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) socket.AddReceivedData(server_response); Socks5Proxy proxy{"proxy.example.com", 1080}; std::string target_hostname = "target.example.com"; std::uint16_t target_port = 80; boost::asio::co_spawn( executor, [&]() -> boost::asio::awaitable { co_await client::impl::ConnectViaProxy(socket, proxy, target_hostname, target_port); auto sent_data = socket.GetSentData(); // Expected client greeting std::string expected_greeting = "\x05\x01\x00"; // Expected CONNECT request std::array expected_request{}; 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 expected_request[req_len++] = static_cast(target_hostname.size()); // domain length std::memcpy(&expected_request[req_len], target_hostname.data(), target_hostname.size()); req_len += target_hostname.size(); std::uint16_t network_order_port = htons(target_port); expected_request[req_len++] = static_cast((network_order_port >> 8) & 0xFF); expected_request[req_len++] = static_cast(network_order_port & 0xFF); std::string expected_data = expected_greeting; auto transformed_view = expected_request | std::views::take(req_len) | std::views::transform([](std::uint8_t byte) { return static_cast(byte); }); expected_data.append(std::ranges::to(transformed_view)); EXPECT_EQ(sent_data, expected_data); co_return; }, boost::asio::detached); io.run(); } /* // Test 3: Connect via system configured proxy TEST_F(ProxyTest, ConnectViaSystemProxy_HttpProxy) { // Set the environment variable for the system proxy const char* original_http_proxy = std::getenv("http_proxy"); setenv("http_proxy", "http://proxy_host:8080", 1); std::string target_host = "target_host"; uint16_t target_port = 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 proxy_response = "HTTP/1.1 200 Connection established\r\n\r\n"; mock_socket.AddReceivedData(proxy_response); bool connect_successful = false; asio::co_spawn(io_context, [&]() -> asio::awaitable { try { SystemConfiguredProxy proxy; co_await client::impl::ConnectToServer(mock_socket, proxy, target_host, target_port); connect_successful = true; } catch (...) { connect_successful = false; } }, asio::detached); io_context.run(); std::string sent_data = mock_socket.GetSentData(); EXPECT_EQ(sent_data, expected_request); EXPECT_TRUE(connect_successful); // Restore the original environment variable if (original_http_proxy) { setenv("http_proxy", original_http_proxy, 1); } else { unsetenv("http_proxy"); } } // Test 4: Incorrect proxy data TEST_F(ProxyTest, ConnectViaHttpProxy_IncorrectData) { HttpProxy proxy{"proxy_host", 8080}; std::string target_host = "target_host"; uint16_t target_port = 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); // Simulate an incorrect response from the proxy server std::string proxy_response = "HTTP/1.1 400 Bad Request\r\n\r\n"; mock_socket.AddReceivedData(proxy_response); bool connect_successful = false; std::string error_message; asio::co_spawn(io_context, [&]() -> asio::awaitable { try { co_await client::impl::ConnectToServer(mock_socket, proxy, target_host, target_port); connect_successful = true; } catch (const std::runtime_error& e) { connect_successful = false; error_message = e.what(); } }, asio::detached); io_context.run(); std::string sent_data = mock_socket.GetSentData(); EXPECT_EQ(sent_data, expected_request); EXPECT_FALSE(connect_successful); EXPECT_FALSE(error_message.empty()); } */