mirror of
https://github.com/yhirose/cpp-httplib
synced 2024-11-21 14:29:10 -07:00
* Fix #1235 * fix BindIPAddress error (#1242) * Code cleanup * Added a unit test * Commented out 'SSLClientTest.SetInterfaceWithINET6' * Fixed incorrect return value from if2ip * Removed if_nametoindex call Co-authored-by: Kotarou <2918558+CyberKoo@users.noreply.github.com>
This commit is contained in:
parent
0857eba17b
commit
cb41947eb4
2 changed files with 48 additions and 16 deletions
27
httplib.h
27
httplib.h
|
@ -170,6 +170,7 @@ using socket_t = SOCKET;
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <ifaddrs.h>
|
#include <ifaddrs.h>
|
||||||
|
#include <net/if.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
@ -2649,11 +2650,14 @@ inline bool bind_ip_address(socket_t sock, const char *host) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_IF2IP
|
#ifdef USE_IF2IP
|
||||||
inline std::string if2ip(const std::string &ifn) {
|
inline std::string if2ip(int address_family, const std::string &ifn) {
|
||||||
struct ifaddrs *ifap;
|
struct ifaddrs *ifap;
|
||||||
getifaddrs(&ifap);
|
getifaddrs(&ifap);
|
||||||
|
std::string addr_candidate;
|
||||||
for (auto ifa = ifap; ifa; ifa = ifa->ifa_next) {
|
for (auto ifa = ifap; ifa; ifa = ifa->ifa_next) {
|
||||||
if (ifa->ifa_addr && ifn == ifa->ifa_name) {
|
if (ifa->ifa_addr && ifn == ifa->ifa_name &&
|
||||||
|
(AF_UNSPEC == address_family ||
|
||||||
|
ifa->ifa_addr->sa_family == address_family)) {
|
||||||
if (ifa->ifa_addr->sa_family == AF_INET) {
|
if (ifa->ifa_addr->sa_family == AF_INET) {
|
||||||
auto sa = reinterpret_cast<struct sockaddr_in *>(ifa->ifa_addr);
|
auto sa = reinterpret_cast<struct sockaddr_in *>(ifa->ifa_addr);
|
||||||
char buf[INET_ADDRSTRLEN];
|
char buf[INET_ADDRSTRLEN];
|
||||||
|
@ -2661,11 +2665,26 @@ inline std::string if2ip(const std::string &ifn) {
|
||||||
freeifaddrs(ifap);
|
freeifaddrs(ifap);
|
||||||
return std::string(buf, INET_ADDRSTRLEN);
|
return std::string(buf, INET_ADDRSTRLEN);
|
||||||
}
|
}
|
||||||
|
} else if (ifa->ifa_addr->sa_family == AF_INET6) {
|
||||||
|
auto sa = reinterpret_cast<struct sockaddr_in6 *>(ifa->ifa_addr);
|
||||||
|
if (!IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr)) {
|
||||||
|
char buf[INET6_ADDRSTRLEN] = {};
|
||||||
|
if (inet_ntop(AF_INET6, &sa->sin6_addr, buf, INET6_ADDRSTRLEN)) {
|
||||||
|
// equivalent to mac's IN6_IS_ADDR_UNIQUE_LOCAL
|
||||||
|
auto s6_addr_head = sa->sin6_addr.s6_addr[0];
|
||||||
|
if (s6_addr_head == 0xfc || s6_addr_head == 0xfd) {
|
||||||
|
addr_candidate = std::string(buf, INET6_ADDRSTRLEN);
|
||||||
|
} else {
|
||||||
|
freeifaddrs(ifap);
|
||||||
|
return std::string(buf, INET6_ADDRSTRLEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
freeifaddrs(ifap);
|
freeifaddrs(ifap);
|
||||||
return std::string();
|
return addr_candidate;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2680,7 +2699,7 @@ inline socket_t create_client_socket(
|
||||||
[&](socket_t sock2, struct addrinfo &ai) -> bool {
|
[&](socket_t sock2, struct addrinfo &ai) -> bool {
|
||||||
if (!intf.empty()) {
|
if (!intf.empty()) {
|
||||||
#ifdef USE_IF2IP
|
#ifdef USE_IF2IP
|
||||||
auto ip = if2ip(intf);
|
auto ip = if2ip(address_family, intf);
|
||||||
if (ip.empty()) { ip = intf; }
|
if (ip.empty()) { ip = intf; }
|
||||||
if (!bind_ip_address(sock2, ip.c_str())) {
|
if (!bind_ip_address(sock2, ip.c_str())) {
|
||||||
error = Error::BindIPAddress;
|
error = Error::BindIPAddress;
|
||||||
|
|
37
test/test.cc
37
test/test.cc
|
@ -1419,10 +1419,9 @@ TEST(InvalidFormatTest, StatusCode) {
|
||||||
TEST(URLFragmentTest, WithFragment) {
|
TEST(URLFragmentTest, WithFragment) {
|
||||||
Server svr;
|
Server svr;
|
||||||
|
|
||||||
svr.Get("/hi",
|
svr.Get("/hi", [](const Request &req, Response & /*res*/) {
|
||||||
[](const Request &req, Response &/*res*/) {
|
EXPECT_TRUE(req.target == "/hi");
|
||||||
EXPECT_TRUE(req.target == "/hi");
|
});
|
||||||
});
|
|
||||||
|
|
||||||
auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
|
auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
|
||||||
|
|
||||||
|
@ -4369,6 +4368,20 @@ TEST(SSLClientTest, WildcardHostNameMatch_Online) {
|
||||||
ASSERT_EQ(200, res->status);
|
ASSERT_EQ(200, res->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
TEST(SSLClientTest, SetInterfaceWithINET6) {
|
||||||
|
auto cli = std::make_shared<httplib::Client>("https://httpbin.org");
|
||||||
|
ASSERT_TRUE(cli != nullptr);
|
||||||
|
|
||||||
|
cli->set_address_family(AF_INET6);
|
||||||
|
cli->set_interface("en0");
|
||||||
|
|
||||||
|
auto res = cli->Get("/get");
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
ASSERT_EQ(200, res->status);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
TEST(SSLClientServerTest, ClientCertPresent) {
|
TEST(SSLClientServerTest, ClientCertPresent) {
|
||||||
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, CLIENT_CA_CERT_FILE,
|
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, CLIENT_CA_CERT_FILE,
|
||||||
CLIENT_CA_CERT_DIR);
|
CLIENT_CA_CERT_DIR);
|
||||||
|
@ -4838,15 +4851,15 @@ TEST(MultipartFormDataTest, LargeData) {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
EXPECT_TRUE(std::string(files[0].name) == "document");
|
EXPECT_TRUE(std::string(files[0].name) == "document");
|
||||||
EXPECT_EQ(size_t(1024 * 1024 * 2), files[0].content.size());
|
EXPECT_EQ(size_t(1024 * 1024 * 2), files[0].content.size());
|
||||||
EXPECT_TRUE(files[0].filename == "2MB_data");
|
EXPECT_TRUE(files[0].filename == "2MB_data");
|
||||||
EXPECT_TRUE(files[0].content_type == "application/octet-stream");
|
EXPECT_TRUE(files[0].content_type == "application/octet-stream");
|
||||||
|
|
||||||
EXPECT_TRUE(files[1].name == "hello");
|
EXPECT_TRUE(files[1].name == "hello");
|
||||||
EXPECT_TRUE(files[1].content == "world");
|
EXPECT_TRUE(files[1].content == "world");
|
||||||
EXPECT_TRUE(files[1].filename == "");
|
EXPECT_TRUE(files[1].filename == "");
|
||||||
EXPECT_TRUE(files[1].content_type == "");
|
EXPECT_TRUE(files[1].content_type == "");
|
||||||
} else {
|
} else {
|
||||||
std::string body;
|
std::string body;
|
||||||
content_reader([&](const char *data, size_t data_length) {
|
content_reader([&](const char *data, size_t data_length) {
|
||||||
|
|
Loading…
Reference in a new issue