mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-26 12:24:46 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d87abeecf0 | ||
|
|
4e28e4f741 | ||
|
|
80a55cedeb | ||
|
|
d05c343602 | ||
|
|
33f67386fe | ||
|
|
56d8168dc4 | ||
|
|
5d87cc0558 | ||
|
|
cb41947eb4 | ||
|
|
0857eba17b | ||
|
|
020b0db090 | ||
|
|
bf0760fde4 |
No files matched your search
+3
-3
@@ -60,10 +60,10 @@
|
|||||||
]]
|
]]
|
||||||
cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR)
|
||||||
|
|
||||||
# Get the user agent and use it as a version
|
# Get the CPPHTTPLIB_VERSION value and use it as a version
|
||||||
# This gets the string with the user agent from the header.
|
# This gets the string with the CPPHTTPLIB_VERSION value from the header.
|
||||||
# This is so the maintainer doesn't actually need to update this manually.
|
# This is so the maintainer doesn't actually need to update this manually.
|
||||||
file(STRINGS httplib.h _raw_version_string REGEX "User\-Agent.*cpp\-httplib/([0-9]+\.?)+")
|
file(STRINGS httplib.h _raw_version_string REGEX "CPPHTTPLIB_VERSION \"([0-9]+\\.[0-9]+\\.[0-9]+)\"")
|
||||||
|
|
||||||
# Needed since git tags have "v" prefixing them.
|
# Needed since git tags have "v" prefixing them.
|
||||||
# Also used if the fallback to user agent string is being used.
|
# Also used if the fallback to user agent string is being used.
|
||||||
|
|||||||
@@ -48,11 +48,6 @@ res->status;
|
|||||||
res->body;
|
res->body;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Try out the examples on Repl.it!
|
|
||||||
|
|
||||||
1. Run server at https://repl.it/@yhirose/cpp-httplib-server
|
|
||||||
2. Run client at https://repl.it/@yhirose/cpp-httplib-client
|
|
||||||
|
|
||||||
SSL Support
|
SSL Support
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
//
|
//
|
||||||
// httplib.h
|
// httplib.h
|
||||||
//
|
//
|
||||||
// Copyright (c) 2021 Yuji Hirose. All rights reserved.
|
// Copyright (c) 2022 Yuji Hirose. All rights reserved.
|
||||||
// MIT License
|
// MIT License
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef CPPHTTPLIB_HTTPLIB_H
|
#ifndef CPPHTTPLIB_HTTPLIB_H
|
||||||
#define CPPHTTPLIB_HTTPLIB_H
|
#define CPPHTTPLIB_HTTPLIB_H
|
||||||
|
|
||||||
|
#define CPPHTTPLIB_VERSION "0.10.6"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configuration
|
* Configuration
|
||||||
*/
|
*/
|
||||||
@@ -170,6 +172,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__
|
||||||
@@ -227,7 +230,7 @@ using socket_t = int;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/md5.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
|
|
||||||
@@ -973,7 +976,7 @@ public:
|
|||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
void set_hostname_addr_map(const std::map<std::string, std::string> addr_map);
|
void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
|
||||||
|
|
||||||
void set_default_headers(Headers headers);
|
void set_default_headers(Headers headers);
|
||||||
|
|
||||||
@@ -1308,7 +1311,7 @@ public:
|
|||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
void set_hostname_addr_map(const std::map<std::string, std::string> addr_map);
|
void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
|
||||||
|
|
||||||
void set_default_headers(Headers headers);
|
void set_default_headers(Headers headers);
|
||||||
|
|
||||||
@@ -2649,11 +2652,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 +2667,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 +2701,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;
|
||||||
@@ -4146,36 +4167,36 @@ inline bool has_crlf(const char *s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
template <typename CTX, typename Init, typename Update, typename Final>
|
inline std::string message_digest(const std::string &s, const EVP_MD *algo) {
|
||||||
inline std::string message_digest(const std::string &s, Init init,
|
auto context = std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)>(
|
||||||
Update update, Final final,
|
EVP_MD_CTX_new(), EVP_MD_CTX_free);
|
||||||
size_t digest_length) {
|
|
||||||
std::vector<unsigned char> md(digest_length, 0);
|
unsigned int hash_length = 0;
|
||||||
CTX ctx;
|
unsigned char hash[EVP_MAX_MD_SIZE];
|
||||||
init(&ctx);
|
|
||||||
update(&ctx, s.data(), s.size());
|
EVP_DigestInit_ex(context.get(), algo, nullptr);
|
||||||
final(md.data(), &ctx);
|
EVP_DigestUpdate(context.get(), s.c_str(), s.size());
|
||||||
|
EVP_DigestFinal_ex(context.get(), hash, &hash_length);
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
for (auto c : md) {
|
for (auto i = 0u; i < hash_length; ++i) {
|
||||||
ss << std::setfill('0') << std::setw(2) << std::hex << (unsigned int)c;
|
ss << std::hex << std::setw(2) << std::setfill('0')
|
||||||
|
<< (unsigned int)hash[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string MD5(const std::string &s) {
|
inline std::string MD5(const std::string &s) {
|
||||||
return message_digest<MD5_CTX>(s, MD5_Init, MD5_Update, MD5_Final,
|
return message_digest(s, EVP_md5());
|
||||||
MD5_DIGEST_LENGTH);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string SHA_256(const std::string &s) {
|
inline std::string SHA_256(const std::string &s) {
|
||||||
return message_digest<SHA256_CTX>(s, SHA256_Init, SHA256_Update, SHA256_Final,
|
return message_digest(s, EVP_sha256());
|
||||||
SHA256_DIGEST_LENGTH);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string SHA_512(const std::string &s) {
|
inline std::string SHA_512(const std::string &s) {
|
||||||
return message_digest<SHA512_CTX>(s, SHA512_Init, SHA512_Update, SHA512_Final,
|
return message_digest(s, EVP_sha512());
|
||||||
SHA512_DIGEST_LENGTH);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -4212,10 +4233,14 @@ class WSInit {
|
|||||||
public:
|
public:
|
||||||
WSInit() {
|
WSInit() {
|
||||||
WSADATA wsaData;
|
WSADATA wsaData;
|
||||||
WSAStartup(0x0002, &wsaData);
|
if (WSAStartup(0x0002, &wsaData) == 0) is_valid_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
~WSInit() { WSACleanup(); }
|
~WSInit() {
|
||||||
|
if (is_valid_) WSACleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_valid_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
static WSInit wsinit_;
|
static WSInit wsinit_;
|
||||||
@@ -6171,7 +6196,8 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req,
|
|||||||
|
|
||||||
#ifndef CPPHTTPLIB_NO_DEFAULT_USER_AGENT
|
#ifndef CPPHTTPLIB_NO_DEFAULT_USER_AGENT
|
||||||
if (!req.has_header("User-Agent")) {
|
if (!req.has_header("User-Agent")) {
|
||||||
req.headers.emplace("User-Agent", "cpp-httplib/0.10.3");
|
auto agent = std::string("cpp-httplib/") + CPPHTTPLIB_VERSION;
|
||||||
|
req.headers.emplace("User-Agent", agent);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -6949,8 +6975,8 @@ inline void ClientImpl::set_follow_location(bool on) { follow_location_ = on; }
|
|||||||
|
|
||||||
inline void ClientImpl::set_url_encode(bool on) { url_encode_ = on; }
|
inline void ClientImpl::set_url_encode(bool on) { url_encode_ = on; }
|
||||||
|
|
||||||
inline void ClientImpl::set_hostname_addr_map(
|
inline void
|
||||||
const std::map<std::string, std::string> addr_map) {
|
ClientImpl::set_hostname_addr_map(std::map<std::string, std::string> addr_map) {
|
||||||
addr_map_ = std::move(addr_map);
|
addr_map_ = std::move(addr_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8075,8 +8101,8 @@ inline size_t Client::is_socket_open() const { return cli_->is_socket_open(); }
|
|||||||
|
|
||||||
inline void Client::stop() { cli_->stop(); }
|
inline void Client::stop() { cli_->stop(); }
|
||||||
|
|
||||||
inline void Client::set_hostname_addr_map(
|
inline void
|
||||||
const std::map<std::string, std::string> addr_map) {
|
Client::set_hostname_addr_map(std::map<std::string, std::string> addr_map) {
|
||||||
cli_->set_hostname_addr_map(std::move(addr_map));
|
cli_->set_hostname_addr_map(std::move(addr_map));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,12 @@ cert2_pem = custom_target(
|
|||||||
command: [openssl, 'req', '-x509', '-config', test_conf, '-key', '@INPUT@', '-sha256', '-days', '3650', '-nodes', '-out', '@OUTPUT@', '-extensions', 'SAN']
|
command: [openssl, 'req', '-x509', '-config', test_conf, '-key', '@INPUT@', '-sha256', '-days', '3650', '-nodes', '-out', '@OUTPUT@', '-extensions', 'SAN']
|
||||||
)
|
)
|
||||||
|
|
||||||
|
key_encrypted_pem = custom_target(
|
||||||
|
'key_encrypted_pem',
|
||||||
|
output: 'key_encrypted.pem',
|
||||||
|
command: [openssl, 'genrsa', '-passout', 'pass:test123!', '-out', '@OUTPUT@', '2048']
|
||||||
|
)
|
||||||
|
|
||||||
cert_encrypted_pem = custom_target(
|
cert_encrypted_pem = custom_target(
|
||||||
'cert_encrypted_pem',
|
'cert_encrypted_pem',
|
||||||
input: key_encrypted_pem,
|
input: key_encrypted_pem,
|
||||||
|
|||||||
+15
-2
@@ -1419,8 +1419,7 @@ 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");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -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);
|
||||||
|
|||||||
Reference in new issue
Block a user